您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > 实验二进程通信 Linux实验报告
实验报告学号_____姓名_______成绩实验二进程通信【实验目的和要求】1、了解进程通信的概念及方法;2、了解信号量、管道;3、掌握信号量、管道和命名管道编程方法。【实验内容】1、利用命名管道实现单机QQ聊天;2、撰写实验报告;【实验原理】1、信号量(semaphore)是为那些访问相同资源的进程以及同一进程不同线程之间提供的一个同步机制。它不是用于传输数据,而只是简单地协调对共享资源的访问。信号量包含一个计数器,表示某个资源正在被访问和访问的次数,用来控制多进程对共享数据的访问。一旦成功拥有了一个信号量,对它所能做的操作只有两种:请求和释放。当执行释放操作时,系统将该信号值减1(如果小于零,则设置为零);当执行请求操作时,系统将该信号值加1,如果加1后的值大于设定的最大值,那么系统将会挂起处理进程,直到信号值小于最大值为止。Tuxedo用信号量来确保在某一时刻只有一个进程对某一块共享内存进程访问。信号量配置太低会导致Tuxedo系统应用程序无法启动。2、管道分为两种:管道和命名管道。管道是UNIX系统IPC的最古老形式,并且所有的UNIX系统都提供这种通信机制。可以在有亲缘关系(父子进程或者是兄弟进程之间)进行通信,管道的数据只能单向流动,如果想双向流动,必须创建两个管道。管道应用的一个重大缺陷就是没有名字,因此只能用于亲缘进程之间的通信。后来以管道为基础提出命名管道(namedpipe,FIFO)的概念,该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(firstinfirstout)规则,对管道及FIFO的读总是从开始处返回数据,对它们的写则是把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。【程序代码】1、lucy.c#includestdio.h#includesys/stat.h#includestring.h#includesys/types.h#includeerrno.h#includefcntl.h#includeunistd.h#includestdlib.hcharwrite_fifo_name[]=ltop_fifo;charread_fifo_name[]=ptol_fifo;charwriter[]=Lucy;charreader[]=Peter;intmain(intargc,char*argv[]){intwrite_fd,read_fd;mkfifo(write_fifo_name,S_IRUSR|S_IWUSR);mkfifo(read_fifo_name,S_IRUSR|S_IWUSR);printf(hello,Iamlucy!\n);write_fd=open(write_fifo_name,O_WRONLY);if(write_fd0){perror(open_w);exit(-1);}read_fd=open(read_fifo_name,O_RDONLY);if(read_fd0){perror(open_r);exit(-1);}pid_tpid;pid=fork();if(pid==0){while(1){charbufw[256]=;printf(%s:,writer);if(fgets(bufw,256,stdin)==NULL)exit(1);bufw[strlen(bufw)-1]='\0';write(write_fd,bufw,strlen(bufw));if(strncmp(bufw,bye,3)==0){close(write_fd);unlink(write_fifo_name);exit(1);}}}else{while(1){charbufr[256]=;read(read_fd,bufr,256);printf(\r%s:%s\n,reader,bufr);if(strncmp(bufr,bye,3)==0){write(write_fd,bye,4);close(read_fd);unlink(read_fifo_name);exit(1);}printf(%s:,writer);fflush(stdout);}}return0;}2、peter.c#includestdio.h#includesys/stat.h#includestring.h#includesys/types.h#includeerrno.h#includefcntl.h#includeunistd.h#includestdlib.hcharwrite_fifo_name[]=ptol_fifo;charread_fifo_name[]=ltop_fifo;charwriter[]=Peter;charreader[]=Lucy;intmain(intargc,char*argv[]){intwrite_fd,read_fd;mkfifo(write_fifo_name,S_IRUSR|S_IWUSR);mkfifo(read_fifo_name,S_IRUSR|S_IWUSR);printf(hello,Iampeter!\n);read_fd=open(read_fifo_name,O_RDONLY);if(read_fd0){perror(open_r);exit(-1);}write_fd=open(write_fifo_name,O_WRONLY);if(write_fd0){perror(open_w);exit(-1);}pid_tpid;pid=fork();if(pid==0){while(1){charbufw[256]=;printf(%s:,writer);if(fgets(bufw,256,stdin)==NULL)exit(1);bufw[strlen(bufw)-1]='\0';write(write_fd,bufw,strlen(bufw));if(strncmp(bufw,bye,3)==0){close(write_fd);unlink(write_fifo_name);exit(1);}}}else{while(1){charbufr[256]=;read(read_fd,bufr,256);printf(\r%s:%s\n,reader,bufr);if(strncmp(bufr,bye,3)==0){write(write_fd,bye,4);close(read_fd);unlink(read_fifo_name);exit(1);}printf(%s:,writer);fflush(stdout);}}return0;}【实验步骤】1、程序lucy.c创建了FIFOwrite_fifo用于向程序peter.c发送消息;peter.c程序创建了FIFOread_fifo用于向lucy.c发送消息;同时,lucy.c能够通过打开peter.c创建的FIFO来得到的peter.c发来的消息,peter.c能够通过打开lucy.c创建的FIFO来得到lucy.c发来的消息。因此两者就能互相通信了,两者必须在线才能进行通信聊天,这个与qq的聊天功能有些类似。2、将lucy.c和peter.c的代码编写完后,在一个终端调试即gcclucy.c–olucy,无错误后运行./lucy;在另外一个新终端上调试即gccpeter.c–opeter,无错误后运行./peter;开始进行聊天,若想结束聊天,则在一个终端上输入bye,俩个终端就会同时关闭。【实验结果】【实验体会】传统的进程间通信方式:无名管道pipe、有名管道fifo和信号signal。管道的编程1、无名管道创建一个简单的管道,可以使用系统调用pipe()。它接受一个参数,也就是一个包括两个整数的数组。如果系统调用成功,此数组将包括管道使用的两个文件描述符。创建一个管道之后,一般情况下进程将产生一个新的进程。系统调用:pipe();注意:fd[0]用于读取管道,fd[1]用于写入管道。该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。一般文件的I/O函数都可以用于管道,如close、read、write等等。2、有名管道创建有名管道用mkfifo()。创建有名管道用mkfifo()。头文件#includesys/stat.h#includesys/types.h函数原型intmkfifo(constchar*pathname,mode_tmode)函数传入值Pathname:要创建的的管道Mode:设置管道权限函数返回值若成功则为0,若出错返回-1FIFO相关出错信息:EACCES(无存取权限)EEXIST(指定文件不存在)ENAMETOOLONG(路径名太长)ENOENT(包含的目录不存在)ENOSPC(文件系统余空间不足)ENOTDIR(文件路径无效)EROFS(指定的文件存在于只读文件系统中)3、信号发送和捕捉信号发送:kill()和raise()kill()函数同读者熟知的kill系统命令一样,可以发送信号给进程或进程组,它不仅可以中止进程(实际上发出SIGKILL信号),也可以向进程发送其他信号。kill()函数语法:头文件#includesignal.h#includesys/types.h函数原型intkill(pid_tpid,intsig)函数传入值Pid:正数:要发送信号的进程号0:信号被发送到所有的当前进程在同一进程组的进程-1:信号发给所有的进程表中的进程-1:信号发给进程组号为-pid的每一个进程Sig:信号函数返回值若成功则为0,若出错返回-1。4、fflush(stdout)目的是清空缓冲,强制结果马上显示到屏幕上。
本文标题:实验二进程通信 Linux实验报告
链接地址:https://www.777doc.com/doc-3268379 .html