linux管道、EPIPE 和 SIGPIPE 的关系「建议收藏」

linux管道、EPIPE 和 SIGPIPE 的关系「建议收藏」试验目的:验证试验过程:

大家好,又见面了,我是你们的朋友全栈君。

试验目的:

1、向管道写端写入数据前,关闭管道写端fd,errno值会是什么?

2、向管道写端写入数据后,关闭管道写端fd,从管道读端读取数据时,是否能正常读取数据?

3、向管道写端写入数据后,关闭管道读端fd,从管道读端读取数据时,会发生什么?errno是什么?

4、向管道写端写入输入前,关闭管道读端fd,是否会触发SIGPIPE信号?程序如何不崩溃?errno值是否会为EPIPE?


正常代码流程:

1、创建一个管道pipefd[2]

2、向管道写端pipefd[1]写入数据

3、从管道读端pipefd[0]读取数据

4、正常关闭管道写端和读端


试验结果:

1、errno=8, 写端fd报:Bad file descriptor。不会触发SIGPIPE, errno也不会为EPIPE

2、可以正常读取到写入的数据

3、和1情况一样。errno=8, 读端fd报:Bad file descriptor。不会触发SIGPIPE, errno也不会为EPIPE

4、会触发SIGPIPE。

如果程序不处理SIGPIPE或者按照默认方式处理SIGPIPE,则程序会退出。

如果忽略SIGPIPE( 使用signal(SIGPIPE, SIG_IGN); ),则程序不会因为系统触发SIGPIPE而退出,会继续执行完。

在向管道写端写入数据时,errno=8, 为EPIPE, 报:Broken pipe


结论:

1、程序中忽略 SIGPIPE信号。

2、向管道写端写入数据时,可以检测errno是否为EPIPE,如果是,可以关闭管道写端fd。


代码:

/*
 * pipe_op.c
 *
 *  Created on: Jun 24, 2014
 *      Author: lingyun
 */


#include "pipe_op.h"

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <bits/signum.h>
#include <signal.h>

#define BUFFER_SIZE 1024

void
pipe_create(int pipefd[2]) {

    int ret;

    ret = socketpair(PF_UNIX, SOCK_STREAM, 0, pipefd);
    assert(ret != -1);
}

void
pipe_close(int pipefd) {
    if (pipefd > 0) {
        close(pipefd);
    }
}

void
pipe_func_test() {

    //忽略SIGPIP信号
    signal(SIGPIPE, SIG_IGN);

    //按照默认处理方式处理SIGPIP信号
    //signal(SIGPIPE, SIG_DFL);

    int pipefd[2];

    pipe_create(pipefd);

    int pipe_read_fd = pipefd[0];
    int pipe_write_fd = pipefd[1];

    printf("pipe read end: %d\n", pipe_read_fd);
    printf("pipe write end: %d\n", pipe_write_fd);

    //write msg to write_pipe, and read from read_pipe

    char buf[BUFFER_SIZE];
    memset(buf, '\0', BUFFER_SIZE);
    const char* message = "hello, i'm lingyun";
    int message_len = strlen(message);
    strncpy(buf, message, message_len);

    printf("buf message: %s\n", buf);

    //1. 向管道写端写数据前, 关闭管道写端fd
    //pipe_close(pipe_write_fd);

    //4. 向管道写端写数据前, 关闭管道读端fd
    pipe_close(pipe_read_fd);

    ssize_t writed = 0;
    writed = write(pipe_write_fd, buf, message_len);

    int save_errno;

    if (writed == -1) {
        save_errno = errno;

        if (errno == EPIPE) {
            printf("pipe_write_fd is closed, write to this fd has EPIPE error\n");
        }
        perror("write");
        goto failed;
    }

    printf("want write message len: %d\n", message_len);
    printf("writed %d char\n", writed);

    memset(buf, '\0', BUFFER_SIZE);
    ssize_t readed = 0;

    //2. 向管道写端写完数据后, 关闭管道写端fd
    //pipe_close(pipe_write_fd);

    //3. 向管道写端写完数据后, 从管道读端读取数据前, 关闭管道读端fd
    //pipe_close(pipe_read_fd);

    readed = read(pipe_read_fd, buf, writed);

    if (readed == -1) {
        save_errno = errno;

        if (errno == EPIPE) {
            printf("pipe_write_fd is closed, read from pipe_read_fd has EPIPE error\n");
        }
        perror("read");
        goto failed;
    }

    printf("want read message len: %d\n", writed);
    printf("readed %d char\n", readed);

    printf("after read, buf message: %s\n", buf);

failed:
    if(pipe_read_fd != -1) {
        pipe_close(pipe_read_fd);
    }

    if(pipe_write_fd != -1) {
        pipe_close(pipe_write_fd);
    }
}

int main() {
    pipe_func_test();
    return 0;
}



版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/139357.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Linux之ant安装部署「建议收藏」

    Linux之ant安装部署「建议收藏」 今天呢,在这里讲下linux环境下ant的部署,废话不多说,直接进入教程。 首先呢,先安装基础环境Java,在这里就不多说了…..不熟悉的小伙伴可以百度找找,很简单的……. 接下来呢,就开始ant的部署,具体分为如下几个步骤:  1.获取介质:       在apache的官网中直接下载,下载地址为:http://ant.apache.org/    …

    2022年7月24日
    17
  • 什么是python标识符?_python语言正确的标识符

    什么是python标识符?_python语言正确的标识符简单地理解,标识符就是一个名字,就好像我们每个人都有属于自己的名字,它的主要作用就是作为变量、函数、类、模块以及其他对象的名称。Python中标识符的命名不是随意的,而是要遵守一定的命令规则,比如说:标识符是由字符(A~Z和a~z)、下划线和数字组成,但第一个字符不能是数字。标识符不能和Python中的保留字相同。有关保留字,后续章节会详细介绍。Python中的标识符中,不能包含空格、@、%以及$等特殊字符。例如,下面所列举的标识符是合法的:UserIDnamemode12

    2025年10月9日
    3
  • 二进制——减法「建议收藏」

    二进制——减法「建议收藏」二进制的减法分为两种:1.使用硬件减法器运算;2.将减法转换成加法运算。 本文讲述第二种方法。 大家都知道计算机有两种数值类型:1.有符号类型;2.无符号类型。 有符号类型是利用其二进制的最高位来存储正负标志的,所以有符号类型的最大值的绝对值要小于无符号类型,就是因为有符号类型比无符号类型少了一位数据位,大小当然就少一半了,但是两种类型所表示的数值的个数是一

    2025年11月19日
    6
  • sqrt函数原型c语言,C语言sqrt函数的实例用法讲解

    sqrt函数原型c语言,C语言sqrt函数的实例用法讲解前言继承是OOP设计中的重要概念。在C++语言中,派生类继承基类有三种继承方式:私有继承(private)、保护继承(protected)和公有继承(public)。一、继承规则继承是C++中的重要特性,派生2021-03-2218:02:41大家有没有在项目中遇到过,将一些预定义的本地结构体转换为Json字符串后,发送到网络中的情形。那我猜想下大家常规的做法:写一个函数,传入结构体的指针,然后…

    2022年5月1日
    76
  • 《JavaScript 模式》读书笔记(6)— 代码复用模式3

    我们之前聊了聊基本的继承的概念,也聊了很多在JavaScript中模拟类的方法。这篇文章,我们主要来学习一下现代继承的一些方法。九、原型继承下面我们开始讨论一种称之为原型继承(prototype

    2022年3月25日
    47
  • 使用ipset来批量控制iptables

    使用ipset来批量控制iptables配置如下1、安装ipsetyuminstallipset2、使用ipset创建列表ipsetcreateserverhash:ip3、添加ipipsetaddserver192.168.1.1ipsetaddserver192.168.1.24、导出ipsetipsetsave>/etc/sysconfig/ipset5、在导出到/etc/

    2022年10月7日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号