Linux进程通信:管道
2011-07-20 13:22
441 查看
使用管道进行进程间通信
jiang@jiang-linux:~/unixprog/2011-3-20$ ./pipe.o
hello,world!#1
hello,world!#2
hello,world!#3
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc fork_pipe.c -o fork_pipe.o;./fork_pipe.o
hello,world!#1
hello,world!#2
hello,world!#3
创建三个进程,2个写,1个读。
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc pipe3.c -o pipe3.o;./pipe3.o
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321
结果不对,不知道为啥,最大的显示是4096,但又写了61440进去。。
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc pipe_size.c -o pipe_size.o;./pipe_size.o
Maximum size of write to pipe:4096 bytes
10240 character in pipe
20480 character in pipe
30720 character in pipe
40960 character in pipe
51200 character in pipe
61440 character in pipe
write bolcked after 65536 characters
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc nonblock_pipe.c -o nonblock_pipe.o;./nonblock_pipe.o
pipe empty
MSG=hello
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=bye!!
End of conversation
如果在父进程中把 close(p[1]);//close pipe write注释掉,表示不要关闭写管道。结果父进程会无阻等待下去:
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc nonblock_pipe.c -o nonblock_pipe.o;./nonblock_pipe.o
pipe empty
MSG=hello
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=bye!!
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
^C
结果:
jiang@jiang-linux:~/unixprog/2011321$ gcc select_pipe.c -o select_pipe.o;./select_pipe.o
Message from child 0
MSG=hello
Message from child 1
MSG=hello
Message from child 2
MSG=hello
Message from child 0
MSG=hello
a
Message from child 1
MSG=hello
Message from child 2
MSG=hello
From statdard input:
a
Message from child 0
MSG=bye!!
Message from child 1
MSG=bye!!
Message from child 2
MSG=bye!!
From statdard input://不知道为什么最后会输出这一句,似乎set没有重置
到管道的写入端,将grep的标准输入连接到管道的输出端。
jiang@jiang-linux:~/unixprog/2011321$ gcc join.c -o join.o;./join.o
dbus-1.0
default.sfx
desktopcouch
directfb-1.2-0
dkms
dpkg
dri
join returned 0
命名管道
FIFO编程:
一个程序用来向命名管道发送信息,一个接收信息。
sendmessage.c
recemessage.c
运行结果:
jiang@jiang-linux:~/unixprog/2011321$ ./recemessage.o &
[1] 2222
jiang@jiang-linux:~/unixprog/2011321$ ./sendmessage.o 'hello''world'
message received:helloworld
jiang@jiang-linux:~/unixprog/2011321$ ./sendmessage.o 'hello' 'world'
message received:hello
message received:world
#include<stdio.h> #include<unistd.h> #define MSGSIZE 16 char *msg1="hello,world!#1"; char *msg2="hello,world!#2"; char *msg3="hello,world!#3"; int main(void) { char inbuf[MSGSIZE]; int p[2],j; /*open pipe */ if(pipe(p)==-1) { perror("pipe call"); } /*write down pipe*/ write(p[1],msg1,MSGSIZE); write(p[1],msg2,MSGSIZE); write(p[1],msg3,MSGSIZE); /*read from pipe*/ for(j=0;j<3;j++) { read(p[0],inbuf,MSGSIZE); printf("%s/n",inbuf); } return 0; }
jiang@jiang-linux:~/unixprog/2011-3-20$ ./pipe.o
hello,world!#1
hello,world!#2
hello,world!#3
父子进程
子进程写,父进程读:#include<stdio.h> #include<unistd.h> #include<stdlib.h> #define MSGSIZE 16 char *msg1="hello,world!#1"; char *msg2="hello,world!#2"; char *msg3="hello,world!#3"; int main(void) { char inbuf[MSGSIZE]; int p[2],j; pid_t pid; /*open file*/ if(pipe(p)==-1) { perror("pipe call"); exit (1); } switch(pid=fork()) { case -1: perror("fork call"); exit (1); case 0: /*if child then close read file descript and writes down the pipe*/ close(p[0]); write(p[1],msg1,MSGSIZE); write(p[1],msg2,MSGSIZE); write(p[1],msg3,MSGSIZE); break; default: /*if parent then closes write file descriptot and reads from the pipe*/ close(p[1]); for(j=0;j<3;j++) { read(p[0],inbuf,MSGSIZE); printf("%s/n",inbuf); } wait(NULL);//?? } exit(0); }
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc fork_pipe.c -o fork_pipe.o;./fork_pipe.o
hello,world!#1
hello,world!#2
hello,world!#3
创建三个进程,2个写,1个读。
#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main(void) { char s[100]; char wribuf1[10]="123456789"; char wribuf2[10]="987654321"; pid_t pid1,pid2,pid3; int p[2],j; if(pipe(p)==-1) { perror("pipe call"); } switch(pid1=fork()) //write pipe { case -1: perror("fork call"); exit (1); case 0: //child1 write pipe for(j=0;j<10;j++) { write(p[1],wribuf1,10); } exit(1); default: break; } switch(pid3=fork()) //child3 write pipe { case -1: perror("fork call"); exit (1); case 0: //child write pipe for(j=0;j<10;j++) { write(p[1],wribuf2,10); } exit(1); default: break; } switch(pid2=fork()) //read pipe { case -1: perror("fork call"); exit (1); case 0: //child write pipe for(j=0;j<100;j++) { read(p[0],s,10); printf("%s/n",s); } exit(1); default: break; } exit(0); }
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc pipe3.c -o pipe3.o;./pipe3.o
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321
管道的容量:
#include<stdlib.h> #include<signal.h> #include<unistd.h> #include<stdio.h> long count; void alrm_action(int signo); int main(void) { int p[2]; long pipe_size; char c='x'; static struct sigaction act; /* set up the signal handler*/ act.sa_handler=alrm_action; sigfillset(&(act.sa_mask)); /*create the pipe */ if(pipe(p)==-1) { perror("pipe call"); exit (1); } /* determine the size of pipe long fpathconf(int fd, int name); _PC_PIPE_BUF returns the size of the pipe buffer, where fd must refer to a pipe or FIFO and path must refer to a FIFO. The corresponding macro is _POSIX_PIPE_BUF. */ pipe_size=fpathconf(p[0],_PC_PIPE_BUF); printf("Maximum size of write to pipe:%ld bytes/n",pipe_size); /*set the signal handler*/ sigaction(SIGALRM,&act,NULL); while(1) { /*set alarm*/ alarm(20); /*write down pipe */ write(p[1],&c,1); /*reset alarm--if no block没有阻塞的话就取消超时*/ alarm(0); if((++count%10240)==0)//if is the multiple of 10240,print information { printf("%ld character in pipe/n",count); } } } void alrm_action(int signo) { printf("write bolcked after %ld characters/n",count); exit(0); }
结果不对,不知道为啥,最大的显示是4096,但又写了61440进去。。
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc pipe_size.c -o pipe_size.o;./pipe_size.o
Maximum size of write to pipe:4096 bytes
10240 character in pipe
20480 character in pipe
30720 character in pipe
40960 character in pipe
51200 character in pipe
61440 character in pipe
write bolcked after 65536 characters
非阻塞读与写
/* nonblock pipe */ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<errno.h> #define MSGSIZE 6 int parent(int *); int child(int *); char *msg1="hello"; char *msg2="bye!!"; int main(void) { int pfd[2]; /*open pipe*/ if(pipe(pfd)==-1) { fatal("pipe call"); } /*set O_NONBLOCK flag for p[0]*/ if(fcntl(pfd[0],F_SETFL,O_NONBLOCK)==-1) { fatal("fcntl call"); } switch(fork()) { case -1: fatal("fork call"); case 0: /*child*/ child(pfd); default: /*parent*/ parent(pfd); } } int parent(int *p) { ssize_t nread; char buf[MSGSIZE]; close(p[1]);//close pipe write for(;;) {//总结:read在读取管道时的返回值似乎跟读文件不太一样 switch(nread=read(p[0],buf,6))//read返回-1表示发生错误,在读管道时表示空 { case -1: /*check to see if nothing is in the pipe */ if(errno==EAGAIN) { printf("pipe empty/n"); sleep(1); break; } case 0://read返回0表示读到文件结构符,在读管道时表示管道关闭。子进程终止后管道的写就关闭了, //父进程的写已经关闭了,所以认为管道关闭了。 /*pipe has been closed */ printf("End of conversation/n"); exit(0); default://read pipe success printf("MSG=%s/n",buf); } } } int child(int *p) { int count; close(p[0]); for(count=0;count<3;count++) { write(p[1],msg1,MSGSIZE); sleep(3); } /*send final message*/ write(p[1],msg2,MSGSIZE); exit (0); } int fatal(char *s) { perror("s"); exit (1); }
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc nonblock_pipe.c -o nonblock_pipe.o;./nonblock_pipe.o
pipe empty
MSG=hello
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=bye!!
End of conversation
如果在父进程中把 close(p[1]);//close pipe write注释掉,表示不要关闭写管道。结果父进程会无阻等待下去:
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc nonblock_pipe.c -o nonblock_pipe.o;./nonblock_pipe.o
pipe empty
MSG=hello
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=bye!!
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
^C
使用select处理多路管道
程序说明:父进程基于管道与三个子进程联系,除此之外,父进程还监听着标准输入。/*server----creates three children and then services them */ #include<stdio.h> #include<sys/time.h> #include<sys/wait.h> #include<stdlib.h> #include<unistd.h> #define MSGSIZE 6 char *msg1="hello"; char *msg2="bye!!"; void parent(int p[][2]); void child(int p[][2],int i); int main(void) { int pip[3][2]; int i; /*create three communication pipes,and spawn three children */ for(i=0;i<3;i++) { if(pipe(pip[i])==-1) { fatal("pipe call"); } switch(fork()) { case -1: //error fatal("fork call"); case 0: //child child(pip,i); } } parent(pip); exit(0); } /*parent sits listening on all three pipes*/ void parent(int p[3][2]) //code for parent { char buf[MSGSIZE],ch; fd_set set,master; int i; /*close all unwanted write file descriptors*/ /* for(i=0;i<3;i++) { close(*(p+i)+1); } */ close(p[0][1]); close(p[1][1]); close(p[2][1]); /*set the bit masks for the select system call*/ FD_ZERO(&master);//initialize the mask pointed to by master*/ FD_SET(0,&master);//set 0:listening stdin for(i=0;i<3;i++) { FD_SET(p[i][0],&master);//listening pipe read } /*select is called with no timeout, * it will block until an event occurs:all child exit * set=master means restore the state */ while(set=master,select(p[2][0]+1,&set,NULL,NULL,NULL)>0)//select的第一个参数不知道什么意思 { /*we mustn't forget information on standard input, * i.e. fd=0 */ if(FD_ISSET(0,&set))//listening stdin { printf("From statdard input:/n"); read(0,&ch,1); printf("%c/n",ch); } for(i=0;i<3;i++) { if(FD_SET(p[i][0],&set)) { if(read(p[i][0],buf,MSGSIZE)>0) { printf("Message from child %d/n",i); printf("MSG=%s/n",buf); } } } /*the server will return to the main program if all * the children have died */ if(waitpid(-1,NULL,WNOHANG)==-1) { return; } } } void child(int p[][2],int i) { int count; close(p[i][0]);//close read pipe for(count=0;count<2;count++)//each child write 2 msg { write(p[i][1],msg1,MSGSIZE); /*pause for a random amount of time*/ sleep(getpid()%4); } /*set final message*/ write(p[i][1],msg2,MSGSIZE); exit(0); } int fatal(char *s) { perror(s); exit(1); }
结果:
jiang@jiang-linux:~/unixprog/2011321$ gcc select_pipe.c -o select_pipe.o;./select_pipe.o
Message from child 0
MSG=hello
Message from child 1
MSG=hello
Message from child 2
MSG=hello
Message from child 0
MSG=hello
a
Message from child 1
MSG=hello
Message from child 2
MSG=hello
From statdard input:
a
Message from child 0
MSG=bye!!
Message from child 1
MSG=bye!!
Message from child 2
MSG=bye!!
From statdard input://不知道为什么最后会输出这一句,似乎set没有重置
管道的例子
展示了管道和exec系统调用的使用,模拟了shell中的管道。难点是理解如何将ls的标准输出连接到管道的写入端,将grep的标准输入连接到管道的输出端。
#include<stdio.h> #include<unistd.h> #include<stdlib.h> /*join---join two commands by pipe*/ int join(char *com1[],char *com2[]) { int p[2],status; /*create child to run commands*/ switch(fork()) { case -1: fatal("1st fork call in join"); case 0: break;//child default://parent wait(&status); return (status);//父进程等待子进程执行完毕后返回状态 } /*remainder of rountine executed by child*/ /*make pipe*/ if((pipe(p))==-1) { fatal("pipe call in join"); } /*create another process*/ switch(fork())//孙进程将标准输出连接到管道的写入端 { case -1: /*error*/ fatal("2nd fork call in fork"); case 0: /*the writing process*/ dup2(p[1],1); //make std.output go to pipe*/ close(p[0]);/*save file descriptors??*/ close(p[1]); execvp(com1[0],com1);//执行程序,将标准输出连接到管道的写入端 /*if execvp returns,error has occured*/ fatal("1st execvp call in join"); default: /*the reading process*/ dup2(p[0],0);//make std.input come from pipe子进程将标准输入连接到管道的写出端 close(p[0]); close(p[1]); execvp(com2[0],com2); fatal("2nd execvp call in join"); } } int main(void) { char *one[4]={"ls","-1","/usr/lib",NULL}; char *two[3]={"grep","^d",NULL}; int ret; ret=join(one,two); printf("join returned %d/n",ret); exit(0); } int fatal(char *s) { perror(s); exit(1); }
jiang@jiang-linux:~/unixprog/2011321$ gcc join.c -o join.o;./join.o
dbus-1.0
default.sfx
desktopcouch
directfb-1.2-0
dkms
dpkg
dri
join returned 0
命名管道
FIFO编程:
一个程序用来向命名管道发送信息,一个接收信息。
sendmessage.c
#include<fcntl.h> #include<stdio.h> #include<errno.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #define MSGSIZE 63 char *fifo="fifo"; int main(int argc,char **argv) { int fd,j,nwrite; char msgbuf[MSGSIZE]; if(argc<2) { fprintf(stderr,"Usage:sendmessage msg.../n"); exit(1); } /*open fifo with O_NONBLOCK set */ if((fd=open(fifo,O_WRONLY|O_NONBLOCK))<0)//非阻塞式打开 { fatal("fifo open failed"); } /*send message*/ for(j=1;j<argc;j++) { if(strlen(argv[j])>MSGSIZE) { fprintf(stderr,"message too long %s/n",argv[j]); continue; } strcpy(msgbuf,argv[j]); if((nwrite=write(fd,msgbuf,MSGSIZE+1))==-1) { fatal("message write failed"); } } exit(0); } int fatal(char *s) { perror(s); exit(1); }
recemessage.c
/*recemessage---receive message via fifo*/ #include<fcntl.h> #include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #define MSGSIZE 63 char *fifo="fifo"; int main(int argc,char **argv) { int fd; char msgbuf[MSGSIZE+1]; /*create fifo,if it doedn't already exist*/ if(mkfifo(fifo,0666)==-1) { if(errno!=EEXIST) { fatal("receiver:mkfifo"); } } /*open fifo for reading and writing*/ if((fd=open(fifo,O_RDWR))<0) { fatal("fifo open failed"); } /*receive message*/ for(;;) { if(read(fd,msgbuf,MSGSIZE+1)<0) { fatal("message read failed"); } /* * printf out message;in read life * something more interesting would * be done */ printf("message received:%s/n",msgbuf); } exit(0); } int fatal(char *s) { perror(s); exit (1); }
运行结果:
jiang@jiang-linux:~/unixprog/2011321$ ./recemessage.o &
[1] 2222
jiang@jiang-linux:~/unixprog/2011321$ ./sendmessage.o 'hello''world'
message received:helloworld
jiang@jiang-linux:~/unixprog/2011321$ ./sendmessage.o 'hello' 'world'
message received:hello
message received:world
相关文章推荐
- Linux下的有名管道(05)---使用两个管道实现两个进程之间的通信(对讲机模式)
- linux基础编程:进程通信之管道
- C/C++:linux进程通信简单例子(管道)
- 命名管道(FIFO) Linux进程进程间的通信之命名管道(FIFO)
- Linux进程间的通信-基于有序文件(匿名管道)
- linux进程间的通信(C): 命名管道
- Linux下的进程通信方式: 管道通信详解
- Linux基础篇 进程通信——管道
- Linux下进程通信之管道
- linux进程间管道通信pipe与fifo
- Linux进程通信 命名管道
- LINUX编程——进程间管道通信
- Linux----进程间通信-管道与两个命名管道实现进程双向通信
- linux进程通信--管道
- Linux进程间的通信——管道
- linux 进程通信 管道
- linux进程通信之使用匿名管道进行父子进程通信
- linux中利用有名管道实现进程之间的通信
- linux的进程通信-管道
- Linux进程通信 标准流管道