一.管道
管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
A. 管道是半双工的,数据只能向一个方向流动;
B. 需要双工通信时,需要建立起两个管道;
C. 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
D. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
匿名管道的创建:该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义;因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信。因此只要两个进程中存在亲缘关系(这里的亲缘关系指的是具有共同的祖先),都可以采用管道方式来进行通信。
#include <unistd.h>
int pipe(int fd[2]);
匿名管道的读写规则:数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。管道两端可分别用描述字fd[0]以及fd[1]来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字 fd[0]表示,称其为管道读端;另一端则只能用于写,由描述字fd[1]来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据 都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等。从管道中读取数据:如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;当管道的写端存在时,
如果请求的字节数目大于PIPE_BUF, 则返回管道中现有数据字节数。下面例子给出了管道的具体应用,父进程通过管道发送一些命令给子进程,子进程解析命令,并根据命令作相应处理。
1 #include <unistd.h> 2 #include <sys/types.h> 3 main() 4 { 5 int pipe_fd[2]; 6 pid_t pid; 7 char r_buf[4]; 8 char** w_buf[256]; 9 int childexit=0; 10 int i; 11 int cmd; 12 13 memset(r_buf,0,sizeof(r_buf)); 14 if(pipe(pipe_fd)<0) 15 { 16 printf("pipe create error\n"); 17 return -1; 18 } 19 if((pid=fork())==0) 20 //子进程:解析从管道中获取的命令,并作相应的处理 21 { 22 printf("\n"); 23 close(pipe_fd[1]); 24 sleep(2); 25 26 while(!childexit) 27 { 28 read(pipe_fd[0],r_buf,4); 29 cmd=atoi(r_buf); 30 if(cmd==0) 31 { 32 printf("child: receive command from parent over\n now child process exit\n"); 33 childexit=1; 34 } 35 36 else if(handle_cmd(cmd)!=0) 37 return; 38 sleep(1); 39 } 40 close(pipe_fd[0]); 41 exit(); 42 } 43 else if(pid>0) 44 //parent: send commands to child 45 { 46 close(pipe_fd[0]); 47 w_buf[0]="003"; 48 w_buf[1]="005"; 49 w_buf[2]="777"; 50 w_buf[3]="000"; 51 for(i=0;i<4;i++) 52 write(pipe_fd[1],w_buf[i],4); 53 close(pipe_fd[1]); 54 } 55 } 56 //下面是子进程的命令处理函数(特定于应用): 57 int handle_cmd(int cmd) 58 { 59 if((cmd<0)||(cmd>256)) 60 //suppose child only support 256 commands 61 { 62 printf("child: invalid command \n"); 63 return -1; 64 } 65 printf("child: the cmd from parent is %d\n", cmd); 66 return 0; 67 }