进程通信—管道

进程通信—管道

概述

    pipe函数创建一个管道,一个可用于进程间通信的单向数据通道。 数组pipefd用于返回两个指向管道两端的文件描述符。 pipefd [0]指的是管道的读取端。 pipefd [1]指的是管道的写入端。 写入管道写入端的数据由内核缓冲,直到从管道的读取端读取。 


接口说明

#include <unistd.h>
int pipe(int pipefd[2]);

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <fcntl.h>              /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);

如果flags为0,则pipe2()与pipe()相同。 以下值可以在标志中按位或运算以获得不同的行为:


O_CLOEXEC

    在两个新的文件描述符上设置close-on-exec(FD_CLOEXEC)标志。 请参阅open函数中同一个标志的说明,这可能有用。


O_DIRECT(自Linux 3.4开始)

    创建一个管道,以“数据包”模式执行I / O。对管道的每个写入(2)都作为一个单独的数据包处理,并且从管道读取(2)将一次读取一个数据包。请注意以下几点:


    *大于PIPE_BUF字节的写入将被拆分为多个数据包。常量PIPE_BUF在<limits.h>中定义。

    *如果read指定的缓冲区大小小于下一个数据包,则读取请求的字节数,并丢弃数据包中的超出字节。指定PIPE_BUF的缓冲区大小将足以读取最大可能的数据包。

    *不支持零长度数据包。 (指定缓冲区大小为零的read是no-op,并返回0.)

    从Linux 4.5开始,可以使用fcntl函数来更改管道文件描述符的O_DIRECT设置。


O_NONBLOCK

    在两个新的打开文件描述中设置O_NONBLOCK文件状态标志。 使用此标志可以节省对fcntl(2)的额外调用,以实现相同的结果。


管道的局限性

1)管道只能在公共的祖先的两个进程之间使用。

2)管道是单向的。



测试用例并说明


测试代码


#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>

static void sig_catch(int signo)
{
        printf("signal caught\n");
        exit(0);
}
int main(int argc, char *argv[])
{

           int pipefd[2];
           pid_t cpid;
           char buf;

           if (argc != 2) {
               fprintf(stderr, "Usage: %s <string>\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           if (pipe2(pipefd,O_NONBLOCK) == -1) {

               perror("pipe");

               exit(EXIT_FAILURE);

           }

           cpid = fork();
           if (cpid == -1) {
               perror("fork");
               exit(EXIT_FAILURE);
           }

           if (cpid == 0) {    /* Child write from pipe */
                        struct sigaction        sa;


                sa.sa_flags = 0;
                sa.sa_handler = sig_catch;
                if (sigaction(SIGPIPE, &sa, NULL) < 0)
                       printf("sigaction failed\n");



                printf("4\n");
               close(pipefd[0]);          /* Close unused read end */
               if(write(pipefd[1], argv[1], strlen(argv[1]))==-1){
                printf("5\n");
                }

               close(pipefd[1]);          /* Reader will see EOF */
                exit(EXIT_SUCCESS);
               
           } else {            /* Parent read argv[1] to pipe */

                printf("1\n");
               close(pipefd[1]);          /* Close unused write end */
                printf("2\n");
               while (read(pipefd[0], &buf, 1) > 0)
                   write(STDOUT_FILENO, &buf, 1);

                printf("3\n");
               write(STDOUT_FILENO, "\n", 1);
               close(pipefd[0]);
               exit(EXIT_SUCCESS);

           }
       }

测试结果

[root@localhost ~]# ./a.out 323

1

2

3


4

signal caught


测试说明

    本例子是用管道+非阻塞来实现的。父进程读取数据后就关闭了管道的读端。由于子进程已经关闭了读端,如果子进程如果再往读端写数据就会出错,并生成一个SIGPIPE信号。

参考资料

[1].http://man7.org/linux/man-pages/man7/pipe.7.html 

[2]. http://man7.org/linux/man-pages/man2/pipe.2.html 


### 操作系统中的管道机制 在操作系统中,进程间通信(IPC)是一个核心概念,用于不同进程之间交换数据。管道是一种简单的IPC形式,在同一台机器上的两个进程之间提供单向的数据流[^1]。 #### 简介 管道分为匿名管道和命名管道两种类型: - **匿名管道**:通常只在同一进程中创建的一对子进程之间使用,具有临时性质。 - **命名管道**:也称为FIFO文件,可以在不相关的进程间建立连接,并且可以跨多个会话持久存在。 #### 创建与操作管道 对于匿名管道而言,Linux/Unix系统的实现方式如下所示: ```c #include <unistd.h> int pipe(int pipefd[2]); ``` 此函数调用会在`pipefd[]`数组中返回一对文件描述符——读端(`pipefd[0]`) 和写端 (`pipefd[1]`). 成功时返回0, 失败则返回-1并设置errno变量来指示错误原因[^2]. 当父进程通过 `fork()` 函数复制自己之后,父子进程可以通过共享这对文件描述符来进行通信: ```c pid_t pid; if ((pid = fork()) == -1) { perror("fork error"); } else if (pid == 0) { /* 子进程 */ close(pipefd[1]); // 关闭不需要的写入端 read(pipefd[0], buf, MAX); // 从管道读取数据到缓冲区buf里 } else { /* 父进程 */ close(pipefd[0]); // 关闭不必要的读取端 write(pipefd[1], msg, strlen(msg)); // 向管道发送消息msg } ``` 上述代码展示了如何利用C语言编写程序片段以展示基本的管道交互过程. #### 命名管道(FIFO) 相比之下,命名管道允许完全无关的应用程序相互通信。要创建一个名为 `/tmp/myfifo` 的 FIFO 文件,可执行以下命令或相应的编程接口: ```bash mkfifo /tmp/myfifo ``` 或者在 C 中使用 mkfifo() 函数: ```c #include <sys/stat.h> mkfifo("/tmp/myfifo", 0666); ``` 一旦建立了这样的特殊文件节点,任何拥有适当权限的过程都可以打开它进行读写访问,就像处理常规文件一样[^3].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值