ImageVerifierCode 换一换
格式:DOCX , 页数:38 ,大小:45.65KB ,
资源ID:29038587      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/29038587.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(进程间通信学习总结李向勇.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

进程间通信学习总结李向勇.docx

1、进程间通信学习总结李向勇姓名:李向勇指导:乔永锋 时间:2015.12.241.管道概述及相关API应用 41.1管道相关概念 41.2管道的创建 41.3管道的读写规则 51.4管道应用实例 91.5管道的局限性 112.有名管道概述及相关API应用 112.1有名管道相关概念 112.2命名管道的创建 122.3命名管道的打开规则 132.4命名管道的读写规则 133. 消息队列概述及API应用 153.1消息队列相关概念 153.2消息缓冲区结构 153.3消息队列API 163.4消息队列优点 184.信号量 194.1信号量概述 194.2信号量数据结构 194.3信号量API 20

2、5. 共享内存概述及API应用 225.1系统V共享内存原理 235.2共享内存API 245.3共享内存的优缺点 266.信号 266.1信号及信号来源 266.2信号的种类 276.2.1可靠信号与不可靠信号 276.2.2实时信号与非实时信号 296.3进程对信号的响应 306.4信号的发送 306.4.1kill()函数 306.4.2alarm()函数 316.5信号的处理 316.5.1signal()函数 316.5.2sigaction()函数 327. 套接口(socket)概述及API应用 327.1重要的数据结构 337.1.1表示套接口的数据结构struct socke

3、t 337.1.2描述套接口通用地址的数据结构struct sockaddr 337.1.3描述因特网地址结构的数据结构struct sockaddr_in: 337.2套接口编程API 347.2.1创建套接口socket() 347.2.2绑定地址bind() 357.2.3请求建立连接connect()(由TCP客户发起) 367.2.4接受连接请求accept()(由TCP服务器端发起) 367.2.5通信函数 377.2.6关闭套接口close() 387.3典型调用 387.3.1典型的TCP服务器代码 387.3.2典型的TCP客户代码 408. 参考资料 40 在Linux下的

4、多个进程间的通信机制叫做IPC,它是多个进程之间进行相互沟通的一种方法。Linux下有多种进程间通信的方法:半双工管道、FIFO(命名管道)、消息队列、信号量、共享内存、套接口。使用这些通信机制可以为Linux下的网络服务器开发提供灵活而又坚固的框架。1.管道概述及相关API应用1.1管道相关概念管道是Linux支持的最初Unix IPC形式之一,具有以下特点:1) 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;2) 能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);3) 只单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文

5、件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。4) 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。1.2管道的创建#include int pipe(int fd2);该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。1.3管道的读写规则

6、管道两端可分别用描述字fd0以及fd1来描述,需要注意的是,管道的两端是固定了任务的。即一端只能用于读,由描述字fd0表示,称其为管道读端;另一端则只能用于写,由描述字fd1来表示,称其为管道写端。如果试图从管道写端读取数据,或者向管道读端写入数据都将导致错误发生。一般文件的I/O函数都可以用于管道,如close、read、write等等。向管道中写入数据: 向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数

7、据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。对管道的写规则的验证1:写端对读端存在的依赖性#include #include #include #include int main(void) int pipe_fd2; pid_t pid; char r_buf4; char* w_buf; int writenum; int cmd; memset(r_buf,0,sizeof(r_buf); if(pipe(pipe_fd)0) sleep(1); /等待子进程完成关闭读端的操作 close(pipe_fd0);/write

8、w_buf=111; if(writenum=write(pipe_fd1,w_buf,4)=-1) printf(write to pipe errorn); else printf(the bytes write to pipe is %d n, writenum); close(pipe_fd1); return 0; 输出结果为: Broken pipe 原因就是该管道以及它的所有fork()产物的读端都已经被关闭。如果在父进程中保留读端,即在写完pipe后,再关闭父进程的读端,也会正常写入pipe。因此,在向管道写入数据时,至少应该存在某一个进程,其中管道读端没有被关闭,否则就会出现

9、上述错误(管道断裂,进程收到了SIGPIPE信号,默认动作是进程终止)。对管道的写规则的验证2:linux不保证写管道的原子性验证#include #include #include #include int main(int argc,char*argv) int pipe_fd2; pid_t pid; char r_buf4096; char w_buf4096*2; int writenum; int rnum; memset(r_buf,0,sizeof(r_buf); if(pipe(pipe_fd)0) close(pipe_fd0);/write memset(r_buf,0,

10、sizeof(r_buf); if(writenum=write(pipe_fd1,w_buf,1024)=-1) printf(write to pipe errorn); else printf(the bytes write to pipe is %d n, writenum); writenum=write(pipe_fd1,w_buf,4096); close(pipe_fd1); return 0;结论:写入数目小于4096时写入是非原子的!如果把父进程中的两次写入字节数都改为5000,则很容易得出下面结论:写入管道的数据量大于4096字节时,缓冲区的空闲空间将被写入数据(补齐),

11、直到写完所有数据为止,如果没有进程读数据,则一直阻塞。1.4管道应用实例实例一:用于shell管道可用于输入输出重定向,它将一个命令的输出直接定向到另一个命令的输入。$kill -l | grep SIGRTMIN lxybjwl-stu:/pipe$ kill -l | grep SIGRTMIN31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+338) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+843) SIGR

12、TMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12实例二:用于具有亲缘关系的进程间通信#include #include #include #include #include #include #include #include /*int pipe(int filedes2);无名管道,返回0成功,返回-1失败*/*fd0为读端,fd1为写端,从尾

13、部写头部读*/*父子进程的无名管道*/int main(void) pid_t pid = -1; int ret = -1; int status = -1; int fd2 = 0;char buf128 = 0; /创建管道 ret = pipe(fd); if(-1 = ret) perror(pipe failed: ); exit(EXIT_FAILURE); /创建子进程 pid = fork(); if(-1 = (ret=pid) perror(fork failed: ); exit(EXIT_FAILURE); /子进程写操作 if(0 = pid) /先关闭读端,以免冲

14、突 close(fd0); /write pipe ret = write(fd1, hello, sizeof(hello); if(-1 = ret) perror(write failed: ); exit(EXIT_FAILURE); else/父进程等待儿子并读 /wait child wait(&status); /先关闭写端,以免冲突 close(fd1); /read pipe ret = read(fd0, buf, sizeof(buf); if(-1 = ret) perror(read failed: ); exit(EXIT_FAILURE); printf(buf

15、= %sn, buf); return 0;1.5管道的局限性管道的主要局限性正体现在它的特点上:1) 只支持单向数据流;2) 只能用于具有亲缘关系的进程之间;3) 没有名字;4) 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);5) 管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;2.有名管道概述及相关API应用2.1有名管道相关概念管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服

16、。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。2.2命名管道的创建有许多种方法可以创建命名管道。其中可以直接用shell来完成。例如,在目录/ipc下建立一个名

17、字为namedfifo的命名管道:lxybjwl-stu:/ipc$ mkfifo namedfifolxybjwl-stu:/ipc$ lsnamedfifolxybjwl-stu:/ipc$ file namedfifo namedfifo: fifo (named pipe)lxybjwl-stu:/ipc$ ls -l namedfifo prw-rw-r- 1 lxy lxy 0 12月 24 20:19 namedfifo可以看出namedfifo属性中有一个p,表示这是一个管道。使用C语言创建FIFO,可以使用mkfifo()函数。#include #include int mk

18、fifo(const char *pathname, mode_t mode);该函数的第一个参数是一个普通的路径名,也就是创建后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。如果mkfifo的第一个参数是一个已经存在的路径名时,会返回EEXIST错误,所以一般典型的调用代码首先会检查是否返回该错误,如果确实返回该错误,那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFO,如close、read、write等等。2.3命名管道的打开规则命名管道比管道多了一个打开操作:open。FIFO的打开规则:如果当前打开操作是为读而打开FIFO

19、时,若已经有相应进程为写而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为写而打开该FIFO(当前打开操作设置了阻塞标志)或者,成功返回(当前打开操作没有设置阻塞标志)。如果当前打开操作是为写而打开FIFO时,如果已经有相应进程为读而打开该FIFO,则当前打开操作将成功返回;否则,可能阻塞直到有相应进程为读而打开该FIFO(当前打开操作设置了阻塞标志);或者,返回ENXIO错误(当前打开操作没有设置阻塞标志)。2.4命名管道的读写规则从FIFO中读取数据:约定:如果一个进程为了从FIFO中读取数据而阻塞打开FIFO,那么称该进程内的读操作为设置了阻塞标志的读操作。如果有

20、进程写打开FIFO,且当前FIFO内没有数据,则对于设置了阻塞标志的读操作来说,将一直阻塞。对于没有设置阻塞标志读操作来说则返回-1,当前errno值为EAGAIN,提醒以后再试。对于设置了阻塞标志的读操作说,造成阻塞的原因有两种:当前FIFO内有数据,但有其它进程在读这些数据;另外就是FIFO内没有数据。解阻塞的原因则是FIFO中有新的数据写入,不论信写入数据量的大小,也不论读操作请求多少数据量。读打开的阻塞标志只对本进程第一个读操作施加作用,如果本进程内有多个读操作序列,则在第一个读操作被唤醒并完成读操作后,其它将要执行的读操作将不再阻塞,即使在执行读操作时,FIFO中没有数据也一样(此时

21、,读操作返回0)。如果没有进程写打开FIFO,则设置了阻塞标志的读操作会阻塞。注:如果FIFO中有数据,则设置了阻塞标志的读操作不会因为FIFO中的字节数小于请求读的字节数而阻塞,此时,读操作会返回FIFO中现有的数据量。向FIFO中写入数据:约定:如果一个进程为了向FIFO中写入数据而阻塞打开FIFO,那么称该进程内的写操作为设置了阻塞标志的写操作。对于设置了阻塞标志的写操作:当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果此时管道空闲缓冲区不足以容纳要写入的字节数,则进入睡眠,直到当缓冲区中能够容纳要写入的字节数时,才开始进行一次性写操作。当要写入的数据量大于P

22、IPE_BUF时,linux将不再保证写入的原子性。FIFO缓冲区一有空闲区域,写进程就会试图向管道写入数据,写操作在写完所有请求写的数据后返回。对于没有设置阻塞标志的写操作:当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。在写满所有FIFO空闲缓冲区后,写操作返回。当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。如果当前FIFO空闲缓冲区能够容纳请求写入的字节数,写完后成功返回;如果当前FIFO空闲缓冲区不能够容纳请求写入的字节数,则返回EAGAIN错误,提醒以后再写。3.消息队列概述及API应用3.1消息队列相关概念消息队列是内核地址空间中

23、的内部链表,通过Linux内核在各个进程之间传递内容。消息顺序的发送到消息队列中,并以几种不同的方式从队列中获取,每个消息队列可以用IPC标识符唯一的进行标识。内核中的消息队列是通过IPC的标识符来区别的,不同的消息队列之间是相对独立的。每个消息队列中的消息,又构成一个独立的链表。3.2消息缓冲区结构struct msgbuflong mtype;/消息类型char mtextSIZE;mtype成员代表消息类型,从消息队列中读取消息的一个重要依据就是消息的类型。mtext是消息内容,当然长度不一定为1。因此,对于发送消息来说,首先预置一个msgbuf缓冲区并写入消息类型和内容,调用相应的发送

24、函数即可;对读取消息来说,首先分配这样一个msgbuf缓冲区,然后把消息读入该缓冲区即可。3.3消息队列API1) 键值构建ftok()函数#include #include key_t ftok(const char* pathname, int proj_id);其中pathname必须是已经存在的目录,而proj_id则是一个8位的值,通常用a、b等表示,返回-1则失败。2) 获得消息msgget()函数#include #include #include int msgget(key_t key, int msgflg);参数key是一个键值,由ftok获得;msgflg参数是一些标志

25、位。该调用返回与健值key相对应的消息队列描述字。在以下两种情况下,该调用将创建一个新的消息队列: 如果没有消息队列与健值key相对应,并且msgflg中包含了IPC_CREAT标志位; key参数为IPC_PRIVATE;3) 发送消息msgsnd()函数#include #include #include int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);向msgid代表的消息队列发送一个消息,即将发送的消息存储在msgp指向的msgbuf结构中,消息的大小由msgze指定。对发送消息来说,有意义的msgfl

26、g标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待。调用返回:成功返回0,否则返回-1。4) 接收消息msgrcv()函数#include #include #include int msgrcv(int msqid, struct msgbuf* msgp, size_t msgsz, long msgtyp, int msgflg);该系统调用从msgid代表的消息队列中读取一个消息,并把消息存储在msgp指向的msgbuf结构中。msqid为消息队列描述字;消息返回后存储在msgp指向的地址,msgsz指定msgbuf的mtext成员的长度(即消息内容的长度),msgtyp为请求读取的消息类型;读消息标志msgflg可以为以下几个常值:IPC_NOWAIT 如果没有满足条件的消息,调用立即返回,此时,errno=ENOMSGIPC_EXCEPT 与msgtyp0配合使用,返回队列中第一个类型不为msgtyp的消息IPC_NOERROR 如果队列中满足条件的消息内容大于所请求的msgsz字节,则把该消息截断,截断部分将丢失。调用返回:成功返回读出消息的实际字节数,否则返回-1。5) 消息控制msgctl()函数#include #include #include sys/msg.h

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1