管道是一种进程间通信的方式,也就是 | 符号的含义


图片来自于xmind导出的svg格式,右键打开图片,查看大图。。。

要讲的东西不多,直接看代码

父子进程通信例子

示例程序

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>

/*
	int fcntl(int fd, int cmd, ... // arg  );
*/

void handler(int signum)
{
	if (signum == SIGPIPE)
	{
		printf("rcv sig %d \n",signum);
		exit(0);
	}
}

int main()
{
	int ret = 0;
	int pipefd[2];
	signal(SIGPIPE, handler);
	/* 
		pipefd[0] 用于读 
		pipefd[1] 用于写 
	*/
	ret = pipe(pipefd);
	if (ret < 0)
	{
		perror("pipe err");
		exit(0);
	}
	pid_t pid;
	pid = fork();
	if (pid == -1)
	{
		perror("fork err");
		exit(0);
	}
	if (pid == 0)
	{
		close(pipefd[0]);
		
		sleep(2);
		write(pipefd[1], "childssssssssssss", 10);

		sleep(2);
		write(pipefd[1], "childssssssssssss", 10);
		
		printf("child quit...\n");
		close(pipefd[1]);
		
		exit(0);
	}
	
	unsigned char buf[1024];
	memset(buf,0,sizeof(buf));
	close(pipefd[1]);
	/*
		fcntl 更改管道描述符属性为非阻塞/阻塞
	*/
	int flag;
	flag = fcntl(pipefd[0], F_SETFL);
	//flag |= O_NONBLOCK;
	flag &= ~O_NONBLOCK;
	fcntl(pipefd[0], F_SETFL, flag);

	ret = read(pipefd[0], buf, sizeof(buf));
	if (ret == -1)
	{
		perror("read err");
	}
	if (ret == 0)
	{
		perror("read err");
	}
	buf[ret] = '\0';
	printf("rcv : %s \n",buf);
	
	close(pipefd[0]);
	wait(NULL);
	printf("parent quit...\n");
	exit(0);
}
  • 子进程关闭读,父进程关闭写,只能有子进程想父进程写数据
  • 子进程向写两次数据
  • 父进程读到第一次的数据之后关闭管道的读端,此时子进程再次写管道会接收到SIGPIPE信号,该信号默认动作是退出进程,这里注册了一个新的信号处理函数
  • 父进程等待子进程退出,父进程退出

实现ls | wc -w

该命令是统计当前目录下文件和目录的单词数

/*
	实现 ls | wc -w
*/

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>


int main()
{
	int ret;
	int pipefd[2];
	
	/* pipefd[0] 用于读 pipefd[1] 用于写 */
	ret = pipe(pipefd);
	if (ret < 0)
	{
		perror("pipe err");
		exit(0);
	}
	pid_t pid;
	pid = fork();
	
	/* 子进程执行ls 写管道 */
	if (pid == 0)
	{
		close(pipefd[0]);
		/* 复制管道的输出到标准输出 */
		dup2(pipefd[1],STDOUT_FILENO);
		close(pipefd[1]);
		
		execlp("ls", "ls", NULL);
		exit(0);
	}
	
	/* 父进程执行wc -c 读管道 */
	else if (pid > 0)
	{
		close(pipefd[1]);
		/* 复制管道的读到标准输入 */
		dup2(pipefd[0],STDIN_FILENO);
		close(pipefd[1]);
		execlp("wc", "wc", "-w", NULL);
	}
	wait(NULL);
	return 0;
}
  • 子进程复制管道的输出替换原来的标准输出,并拉起ls程序
  • 父进程复制管道的输入替换原来的标准输入,并拉起wc -w程序

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

IPC机制 上一篇
socket应用编程(2) 下一篇