Linux系统编程札记:进程通信(一)
进程简单来讲就是一个程序的一次执行,这里说的进程一般都指的是运行在用户态的进程,而处于用户态的不同进程之间是彼此相互隔离的,它们必须通过某种方式来进行通信,具体理由如下:
(1)数据传输:有时候一个进程需要将它的数据发送给另一个进程。
(2)资源共享:有时候多个进程之间需要共享同样的资源。
(3)通知事件:有时候一个进程需要向另一个或一组进程发送消息,通知它们发生了某个事件。
(4)进程控制:有些进程希望能够完全控制另一个进程的执行,此时控制进程希望能够拦截另一进程的所有操作,并能够及时知道它的状态改变。
1.进程间通信的方式:
进程间通信的方式总共有6种:
(1)管道通信(包括有名管道和无名管道)
(2)信号通信
(3)消息队列通信
(4)共享内存通信
(5)信号量通信
(6)套接字(socket)通信
2.管道通信:
提到管道这个词,个人认为你可以把其想象成一根运输数据的管子,它把一个进程的输出和另一个进程的输入联系在一起,一个进程从管道的尾部写入数据,另一个进程从管道的头部读取数据,管道中的数据被进程读出来以后将被从管道中删除,其他的进程将不能再次读到这些数据。
管道提供了简单的流控制机制,进程试图读取没有数据的空管道时将会被阻塞,同样如果管道中数据的容量已满时,如果这时候有一个进程试图向这个管道写数据时,那么同样也会被阻塞。
管道通信有两种方式:一是无名管道通信,二是有名管道通信,无名管道只能用于父进程和子进程之间的通信,而有名管道能用于同一系统中任意两个进程之间的通信。
2.1 无名管道的创建:
创建无名管道可以使用系统调用pipe,其原型为:
int pipe(int filedis[2])
filedis[2]:管道的文件描述符,我们可以把管道的头部和尾部各看作是一个文件,其中向管道尾部写数据所对应的文件描述符为filedis[1],向管道头部读取数据所对应的文件描述符为filedis[0]。
无名管道创建成功时返回0,否则返回-1 。
使用pipe系统调用创建无名管道时需要包含的头文件为:
#include <unistd.h>
2.2 无名管道的关闭:
关闭一个无名管道只需要使用close系统调用将filedis[0]和filedis[1]这两个文件描述符关闭即可。
2.3 无名管道的读写:
无名管道只能用于父进程和子进程之间进行通信,因此对无名管道进行读写时,通常会先通过pipe创建一个无名管道,然后再使用fork创建一个子进程,该子进程会继承父进程所创建的管道。
注:必须在fork之前就调用pipe函数创建一个无名管道,否则就会出现子进程和父进程各会创建一个管道,父子两个进程都没有共用同一根管道,在这种情况下是无法通信的。
无名管道的读写模型
2.4 无名管道编程:
/*在父进程中创建一无名管道,并创建子进程来读该管道,父进程来写该管道*/ #include <unistd.h> #include <sys/types.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc,char*argv[]) { /*存储创建无名管道后返回的两个文件描述符 pipe_fd[0]用于读管道,pipe_fd[1]用于写管道*/ int pipe_fd[2]; pid_t pid; char buffer_r[100]; //缓冲区 int real_read_num; memset(buffer_r,0,sizeof(buffer_r));//把缓冲区清0 if(pipe(pipe_fd)<0) //创建无名管道 { printf("create pipe failure!\n"); exit(1); } else { printf("create pipe sucess!\n"); } pid=fork(); if(pid==-1) { printf("create fork process error!"); } else if(pid==0)//子进程 { //printf("This is the child process!\n"); close(pipe_fd[1]); //关闭管道写端 sleep(2); //子进程睡眠2秒,先让父进程执行往管道里面写入数据 if((real_read_num=read(pipe_fd[0],buffer_r,100))>0) //读取管道里面的数据 { printf("%d numbers read from the pipe is %s\n",real_read_num,buffer_r); } close(pipe_fd[0]);//子进程读取管道结束,关闭管道读端 exit(0); } else //父进程 { //printf("This is the father process!\n"); close(pipe_fd[0]);//关闭管道读端 if(write(pipe_fd[1],"Hello ",6)!=-1)//往管道里面写入数据 { printf("father process write1 Hello\n"); } if(write(pipe_fd[1],"Pipe!",5)!=-1) { printf("father process write2 Pipe!\n"); } close(pipe_fd[1]); //sleep(10);//此时子进程开始执行,去管道里面去读取数据 waitpid(pid,NULL,0);//等待子进程结束 exit(0); } return 0; }
2.5 有名管道的创建:
创建有名管道可以使用系统调用mkfifo,其原型为:
int mkfifo(const char*pathname,mode_t mode)
pathname:创建的有名管道的名字,可以包含路径,缺省情况下为当前路径(有名管道实质上就是一个文件)
mode_t:创建的文件的属性(有名管道实质上就是一个文件)
创建有名管道成功时,函数返回0,否则返回-1 。
使用mkfifo系统调用来创建一个有名管道应该包含头文件:
#include <sys/types.h>
#include <sys/stat.h>
2.6 有名管道的关闭:
要关闭有名管道,同样是使用系统调用close关闭有名管道所对应的文件描述符即可。
2.7 有名管道编程:
fifo_write.c :创建一个有名管道并往里面写入一些数据
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define FIFO_SERVER "./myfifo" //创建的有名管道保存在当前目录下 int main(int argc,char*argv[]) { int fifo_fd; char buffer[100];//缓冲区 /*创建有名管道*/ if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) { printf("can‘t create fifo_server!\n"); exit(1); } /*打开有名管道,有名管道实质上就是一个文件*/ fifo_fd=open(FIFO_SERVER,O_RDWR|O_NONBLOCK); if(fifo_fd==-1) { printf("Open fifo_server error!\n"); exit(1); } /*判断运行程序时是否有参数传入*/ if(argc==1) { printf("Please send something!\n"); exit(1); } strcpy(buffer,argv[1]); //把传入的参数复制到缓冲区 /*将缓冲区里的数据写进有名管道*/ if(write(fifo_fd,buffer,100)==-1) { printf("write fifo_server error!maybe the fifo_server is full!\n"); exit(1); } else { printf("write %s to the fifo_server!\n",argv[1]); } close(fifo_fd); //关闭有名管道 return 0; }
fifo_read.c :从fifo_write.c文件创建的有名管道中读取数据
#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define FIFO "./myfifo" int main(int argc,char*argv[]) { char buffer[100]; int fifo_fd; int real_read_num; fifo_fd=open(FIFO,O_RDONLY|O_NONBLOCK);//打开有名管道 if(fifo_fd==-1) { printf("Open fifo error!\n"); exit(1); } /*设计一个死循环不断从有名管道里读取数据*/ while(1) { memset(buffer,0,100); //将缓冲区清0 if((real_read_num=read(fifo_fd,buffer,100))==-1) { printf("read from fifo_server error! the fifo_server has no data!\n"); exit(1); } else { printf("read %s from fifo_server!\n",buffer); sleep(1); } } close(fifo_fd); pause(); unlink(FIFO); return 0; }
暂时写到这里,待续。
本文出自 “止不住的思考” 博客,请务必保留此出处http://9110091.blog.51cto.com/9100091/1605410
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。