进程通信(管道)

本文探讨了管道作为进程间通信方式的特点,包括其半双工特性、适用范围及独特的文件系统属性。通过实例演示了如何在父子进程中实现数据传输,并强调了在进行管道写操作时必须保证至少有一个读端未关闭的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道; 

2. 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

3. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中;

4. 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

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

int main()
{
	int pipe_fd[2];
	pid_t pid;
	char r_buf[100];
	char w_buf[4];
	char * p_wbuf;
	int r_num;
	int cmd;
	memset(r_buf, 0, sizeof(r_buf));
	memset(w_buf, 0, sizeof(r_buf));
	p_wbuf = w_buf;
	if (pipe(pipe_fd) < 0) {
		printf("pipe create error\n");
		return -1;
	}
	if ((pid = fork()) == 0) {
		close(pipe_fd[1]);
		sleep(3); /* 确保父进程关闭写端 */
		r_num = read(pipe_fd[0], r_buf, 100);
		printf( "read num is %d the data read from the pipe is %d\n", r_num, atoi(r_buf));
		close(pipe_fd[0]);
		exit(0);
	} else if (pid > 0) {
		close(pipe_fd[0]); /* read */
		strcpy(w_buf, "111");
		if (write(pipe_fd[1], w_buf, 4) != -1)
			printf("parent write over \n");
		/* 管道写端关闭后,写入的数据将一直存在,直到读出为止 */
		close(pipe_fd[1]); /* write */
		printf("parent close fd[1] over\n");
		sleep(10);
	}
	return 0;
}

对管道的写规则的验证1:写端对读端存在的依赖性

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
int main()
{
	int pipe_fd[2];
	pid_t pid;
	char r_buf[4];
	char * w_buf;
	int writenum;
	int cmd;
	memset(r_buf, 0, sizeof(r_buf));
	if (pipe(pipe_fd) < 0) {
		printf("pipe create error\n");
		return -1;
	}
	if ((pid = fork()) == 0) {
		close(pipe_fd[0]);
		close(pipe_fd[1]);
		sleep(10); 
		exit(0);
	} else if (pid > 0) {
		sleep(1); /* 等待子进程完成关闭读端的操作 */
		close(pipe_fd[0]); /* write */
		w_buf = "111";
		if ((writenum = write(pipe_fd[1], w_buf , 4)) == -1)
			printf("write to pipe error\n");
		else 
			printf("the bytes write to pipe is %d\n", writenum);
		close(pipe_fd[1]);
	}
	return 0;
}

则输出结果为: Broken pipe,原因就是该管道以及它的所有fork()产物的读端都已经被关闭。如果在父进程中保留读端,即在写完pipe后,再关闭父进程的读端,也会正常写入pipe,读者可自己验证一下该结论。因此,在向管道写入数据时,至少应该存在某一个进程,其中管道读端没有被关闭,否则就会出现上述错误(管道断裂,进程收到了SIGPIPE信号,默认动作是进程终止)


### 操作系统中的管道机制 在操作系统中,进程间通信(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、付费专栏及课程。

余额充值