Linux下的进程间通信之管道
2016-09-06 15:51
260 查看
在Linux下,每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到所以进 程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication).
1、管道(pipe)
管道是一种最基本的IPC机制,由pipe函数创建:
调⽤用pipe函数时在内核中开辟一块缓冲区(称为管道)⽤用于通信,它有⼀一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。 开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信:
在一个进程调用pipe函数创建管道,得到两个文件描述符指向读端和写段。
进程调用fork()创建子进程,那么子进程会继承父进程的文件描述符,所以子进程也有两个文件描述符指向管道两端。因为管道只能进行单向通信,所以关闭父进程的读端和子进程的写端(也可以关闭父进程写端和子进程读端)。如下图
这是创建管道进行通信的过程,管道创建好之后再写端写入,在读端就可以读到写入的数据。下面编写代码进行测试。
运行结果如图:
其中“i am child”每隔一秒打印一次。
使⽤用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):
1. 如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读后,再次read会返回0,就像读到文件末尾一样。
2. 如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
3. 如果所有指向管道读端的⽂文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。
4. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写⼊入数据并返回。
1、管道(pipe)
管道是一种最基本的IPC机制,由pipe函数创建:
#include <unistd.h> int pipe(int filedes[2]);
调⽤用pipe函数时在内核中开辟一块缓冲区(称为管道)⽤用于通信,它有⼀一个读端一个写端,然后通过filedes参数传出给用户程序两个文件描述符,filedes[0]指向管道的读端,filedes[1]指向管道的写端(很好记,就像0是标准输入1是标准输出一样)。所以管道在用户程序看起来就像一个打开的文件,通过read(filedes[0]);或者write(filedes[1]);向这个文件读写数据其实是在读写内核缓冲区。pipe函数调用成功返回0,调用失败返回-1。 开辟了管道之后如何实现两个进程间的通信呢?比如可以按下面的步骤通信:
在一个进程调用pipe函数创建管道,得到两个文件描述符指向读端和写段。
进程调用fork()创建子进程,那么子进程会继承父进程的文件描述符,所以子进程也有两个文件描述符指向管道两端。因为管道只能进行单向通信,所以关闭父进程的读端和子进程的写端(也可以关闭父进程写端和子进程读端)。如下图
这是创建管道进行通信的过程,管道创建好之后再写端写入,在读端就可以读到写入的数据。下面编写代码进行测试。
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<errno.h> 4 #include<string.h> 5 6 int main() 7 { 8 int _pipe[2]; 9 int ret=pipe(_pipe); //创建管道 10 if(ret==-1) 11 { 12 printf("create pipe error!"); 13 return 1; 14 } 15 16 pid_t id=fork(); //创建子进程 17 if(id<0) 18 { 19 printf("fork error!"); 20 return 2; 21 } 22 else if(id==0) //子进程 23 { 24 close(_pipe[0]); //关闭读端 25 int i=0; 26 char *_mesg_c=NULL; 27 while(i<100) 28 { 29 _mesg_c="i am child"; 30 write(_pipe[1],_mesg_c,strlen(_mesg_c)+1); 31 sleep(1); 32 i++; 33 } 34 } 35 else //父进程 36 { 37 close(_pipe[1]); //关闭写端 38 char _mesg[100]; 39 int j=0; 40 while(j<100) 41 { 42 memset(_mesg,'\0',sizeof(_mesg)); 43 read(_pipe[0],_mesg,sizeof(_mesg)); 44 printf("%s\n",_mesg); 45 j++; 46 } 47 } 48 return 0; 49 }
运行结果如图:
其中“i am child”每隔一秒打印一次。
使⽤用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):
1. 如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读后,再次read会返回0,就像读到文件末尾一样。
2. 如果有指向管道写端的文件描述符没关闭(管道写端的引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
3. 如果所有指向管道读端的⽂文件描述符都关闭了(管道读端的引用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。
4. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写⼊入数据并返回。
相关文章推荐
- Linux socket 初步
- Linux Kernel 4.0 RC5 发布!
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- Linux 下无损图片压缩小工具介绍