《linux进程之间的通信.ppt》由会员分享,可在线阅读,更多相关《linux进程之间的通信.ppt(25页珍藏版)》请在三一办公上搜索。
1、进程之间的通信,2023/11/8,Linux内核源代码导读,2,1、实验目的为了理解和掌握UNIX和Linux进程通信系统调用的功能,这里给出了进程通信实现机制中使用的系统调用命令的格式和如何利用系统调用命令进行进程通信编程,以便通过学习,提高学生对进程通信系统调用的编程能力。,实验目的和要求,2023/11/8,Linux内核源代码导读,3,2、实验要求书写实验报告,应该包括如下内容:(1)实验题目。(2)程序中使用的数据结构及主要符号说明。(3)程序流程图和带有注释的源程序。(4)执行程序名,并打印程序运行时的初值和运行结果。(5)通过实验后的收获与体会及对实验的改进意见和见解。,实验目
2、的和要求,2023/11/8,Linux内核源代码导读,4,通过使用管道实现两个或多个进程之间的通信。所谓管道,就是将一个进程的标准输出与另一个进程的标准输入联系在一起,进行通信的一种方法。同组进程之间可用无名和有名管道进行通信,而不同组进程之间只能通过有名管道进行通信。管道通信是进程之间使用文件系统中的文件,按先进先出方式进行同步传输数据的方法。例如,管道在Linux命令行中的应用如下:$ls|sort|head-5,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,5,该命令行实现将当前目录的文件列表、排序,且只输出前5行。一、无名管道通信1、创建无名管道的pipe()函
3、数pipe()函数成功时,内核将返回打开文件的两个描述字。一个作为管道的输入端,另一个作为管道的输出端。(1)pipe()函数调用格式如下:#includeint pipe(int fdes2);,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,6,参数:fdes2数组存放返回的两个文件描述符。返回值:正确返回0,错误返回-1。使用无名管道通信时,是使用临时文件的方式实现进程之间的批量数据传输。若通信双方不是父子关系,不能直接建立通信联系。必须由父进程先创建一个管道,再创建需要通信的两个子进程,两者是通过复制父进程映像使两者建立联系的。(2)无名管道pipe()的使用示例使
4、用无名管道pipe(),父子进程之间的通信的源程序如下:,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,7,/*pipe.c源程序*/#include#include#include#includeconst char parent=“A message to pipes communicaton.n”main()int pid,w_n,r_n,chan12;char bufBUFSIZE;pipe(chan1);pid=fork();if(pid0)printf(“to create child error.n”);exit(1);,进程之间管道通信机制,2023/11
5、/8,Linux内核源代码导读,8,if(pid0)close(chan10);/*父进程关闭读通道*/w_n=write(chan11,parent,strlen(parent);close(chan11);printf(“parent process waits the child to terminate.n”);wait(0);printf(“parent process terminates.n”);else close(chan11);/*子进程关闭写通道*/r_n=read(chan10,buf,BUFSIZE);printf(“The message read by child
6、 process is:%s.reads bytes is%d.n”,buf,r_n);close(chan10);printf(“child process terminates.n”);,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,9,当父进程首先被调用时,该程序运行结果是:parent process sends 46 bytes message to child.parent process waits child to terminate.然后父进程阻塞等待子进程终止。系统调用子进程运行,输出如下信息:The message read by child pro
7、cess is:A message to pipes communication.Reads bytes is 46.child process terminates.然后父进程被唤醒调度运行,输出如下信息后程序退出:parent process terminates.,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,10,本例中,父进程使用pipe(chan1)系统调用打开一个无名管道,之后创建一个子进程,子进程复制父进程的打开文件表。为了正确通信,父进程关闭读通道close(chan10),子进程关闭写通道close(chan11)。父进程向管道写,子进程从管道读。完成
8、一次通信后,父子进程分别关闭自己的写/读通道,管道文件消失。思考:试分析该程序运行可能产生的其他结果。,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,11,2、popen()和pclose()函数系统提供了创建管道的简单函数popen()和pclose()。当使用这两个函数对管道操作时,所有复杂的操作,如创建管道、fork()子进程、关闭管道的无用端,执行一个shell命令,等待命令执行完成后返回等操作都在系统内部自动完成。(1)popen()和pclose()函数的调用格式如下:#includeFILE popen(const char cmdstring,const
9、char*open_mode);int pclose(FILE*fp);其中,cmdstring是shell要求的包括参数和选项的一个完整的命令行。open_mode指出管道访问方式:读(“r”)或写(“w”)。,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,12,返回值:popen()函数正确返回文件结构的指针,错误返回空指针NULL;pclose()函数正确返回cmdstring结束时的退出状态,错误返回-1。popen()函数先执行fork()函数创建一个子进程,然后调用exec()函数执行命令cmdstring,并且返回一个标准I/O文件指针。若open_mode
10、为“r”,那么管道的输入端与命令行cmdstring的标准输出端相连,即父进程以“r”方式打开管道并成功获得管道文件的指针,用于从管道读。被创建的子进程执行cmdstring命令行,向管道输出,具体可见下图1所示。,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,13,若open_mode为“w”,那么管道的输出端与命令行cmdstring的标准输入端相连,即父进程以“w”方式打开管道并成功地获得管道文件的指针,用于向管道写,被创建的子进程从管道读入,以完成命令行的执行,如图2所示。,进程之间管道通信机制,父进程fp,系统内核,管道,子进程(执行cmdstring)stdi
11、n,图1 父进程执行fp=popen(cmdstring,”r”)的示意图,图2 父 进程执行fp=popen(cmdstring,”w”)的示意图,2023/11/8,Linux内核源代码导读,14,(2)以命令行为参数的管道文件的示例。/*popen.c源程序*/#include#include#include#includeint main()char bufBUFSIZE+1;int char_n;FILE*fpin;if(fpin=popen(“wc-l popen.c”,”r”)=NULL)/父进程由于读管道printf(stderr,”popne command cant ope
12、n!n”);exit(1);,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,15,/*从文件中读出数据,写入管道中*/while(char_n=fread(buf,sizeof(char),strlen(buf),fpin)0)bufchar_n-1=0;printf(“The number of reading lines is:%s.n”,buf);pclose(fpin);exit(0);运行结果:The number of reading line is 23.说明:先打开文本文件,通过函数popen创建一个可读管道,将命令“wc-l popen.c”的输出与管道
13、的输入端连接起来,然后从管道读数据,那么,命令行就可以通过管道接收文本文件的数据了。,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,16,二、有名管道的通信1、创建一个有名管道的系统调用mkdfifo()有名管道的使用方式与无名管道不同。有名管道可被任何知道其名字的进程打开和使用。为了使用有名管道,进程要先建立它,并与它的一端相连,创建有名管道的进程叫服务器进程,存取管道的其他进程叫客户进程。通信双方必须首先创建有名管道后,才能打开进行读写。当文件不再需要时,要显式删除。调用格式如下:,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,17,#inclu
14、de#include#include#includeint mknod(const char*pathname,mode_t mode,dev_t dev);或#include#includeint mkfifo(const char*pathname,mode_t mode);其中pathname是新创建的有名管道的文件路径名,mode是被创建文件的类型和存取方式,dev是文件所在的设备。对于有名管道,dev这个参数是0。,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,18,这两个系统调用隐含指定以“O_CREAT|O_EXCL”方式,创建一个新的FIFO文件。返回值:
15、成功时,返回0;不成功时(即文件已经存在),返回-1。2、打开一个有名管道由于有名管道创建时并没有打开,因此必须显式地使用如下的系统调用将文件打开:open(pathname,oflg);其中,pathname是要打开的有名管道的路径名,oflg是文件打开时的存取方式。打开一个有名管道与一个普通文件没有区别,只是通信的发送者以OWRONLY只写方式、接收方以ORDONLY只读方式打开。,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,19,进程间使用有名管道实现通信时,必须有三次同步:第一次是打开同步。当一个进程以读方式打开有名管道时,若已有写者打开过,则唤醒写者后继续前进
16、,否则,睡眠等待写者。当一个进程以写方式打开有名管道时,若已有读者打开过,则唤醒读者后继续前进,否则等待读者。第二次是读写同步。其同步方式与pipe相同,运行写者超前读者1024个字符。当一次写超过1024时,超过的字符要写入时,则写者必须等待。读者从有名管道读时,若没有数据可读则等待。若有数据可读,读完后要检查有无写者等待,若有唤醒写者。而且要求读写两方要随时检查通信的另一方是否还存在,一旦有一方不存在,应立即终止通信过程。,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,20,第三次是关闭同步。当一个写进程关闭有名管道时,若发现有进程睡眠等待从管道读,则唤醒它,被唤醒进
17、程立即从读调用返回。当一个读进程关闭有名管道时,若发现有进程睡眠等待向管道写,则唤醒它,并向它发一个指示错误条件的信号后返回。最后一个关闭有名管道的基础,释放该管道占用的全部盘块及相应主存i节点。有名管道打开后,就可以使用文件的读写命令进行读写,读写完成后就立即关闭。有名管道文件关闭后,文件本身并没有消失。有名管道的读、写和关闭动作与普通玩家完全相同。,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,21,3、有名管道的使用示例/*fifo1.c 有名管道源程序*/#includechar string=“this is a example to show fifo com
18、munication”;main(argc,argv)int argc;char*argv;int fd;char buf256;int i;mkfifo(“fifo”,010777,0);/创建属性为010777的管道文件/其中,010为管道文件的类型,777为允许的访问属性if(argc=2),进程之间管道通信机制,2023/11/8,Linux内核源代码导读,22,fd=open(“fifo”,O_WRONLY);elsefd=open(“fifo”,O_RDONLY);for(i=0;i3;i+)if(argc=2)write(fd,string,sizeof(string);prin
19、tf(“n I have wrote:%s to pipe.”string);else,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,23,read(fd,buf,sizeof(string);printf(“nThe context of fifo by I have read is:%s”,buf);close(fd);exit(0);在命令行格式中,一个进程使用“./a.exe 1&”在后台运行,而另一个进程使用“./a.exe”在前台运行。实现两者的通信。运行该程序,程序的输出结构如下:The context of fifo by I have read is:this is a example to show fifo communication!I have wrote:this is a example to show fifo communication!,进程之间管道通信机制,2023/11/8,Linux内核源代码导读,24,习题:编写一个有名管道程序。一个(客户)进程从键盘循环读一系列字符,将这些字符和发送者的pid发给服务器进程,让其统计输入的是字符还是数字,分别为多少个,完成后再向客户进程发回服务的结果,由客户进程输出。,进程之间管道通信机制,Thanks!,The end.,