linux消息队列进程通信.doc





《linux消息队列进程通信.doc》由会员分享,可在线阅读,更多相关《linux消息队列进程通信.doc(22页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、linux消息队列进程通信 一、消息队列的基本概念消息队列(也叫做报文队列)是Unix系统V版本中3种进程间通信机制之一。另外两种是信号灯和共享内存。这些IPC机制使用共同的授权方法。只有通过系统调用将标志符传递给核心之后,进程才能存取这些资源。这种系统IPC对象使用的控制方法和文件系统非常类似。使用对象的引用标志符作为资源表中的索引。 消息队列就是一个消息的链表。就是把消息看作一个记录,并且这个记录具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读出消息。Linux采用消息队列的方式来实现消息传递。这种消息的发送
2、方式是:发送方不必等待接收方检查它所收到的消息就可以继续工作下去,而接收方如果没有收到消息也不需等待。这种通信机制相对简单,但是应用程序使用起来就需要使用相对复杂的方式来应付了。新的消息总是放在队列的末尾,接收的时候并不总是从头来接收,可以从中间来接收。消息队列是随内核持续的并和进程相关,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。因此系统中记录消息队列的数据结构(structipc_idsmsg_ids)位于内核中,系统中的所有消息队列都可以在结构msg_ids中中找到访问入口。IPC标识符:每一个IPC目标都有一个唯一的IPC标识符。这里所指的IPC目标是指一个单独
3、的消息队列、一个信号量集或者一个共享的内存段。系统内核使用此标识符在系统内核中指明IPC目标。IPC关键字:想要获得唯一的标识符,则必须使用一个IPC关键字。客户端进程和服务器端进程必须双方都同意此关键字。这是建立一个客户机/服务器框架的第一步。在SystemVIPC机制中,建立两端联系的路由方法是和IPC关键字直接相关的。通过在应用程序中设置关键字值,每一次使用的关键字都可以是相同的。一般情况下,可以使用ftok()函数为客户端和服务器端产生关键字值。二、ipcs命令命令ipcs用于读取SystemVIPC目标的状态。ipcs-q:只显示消息队列。ipcs-s:只显示信号量。ipcs-m:只
4、显示共享内存。ipcshelp:其他的参数。三、消息队列的主要调用 内核中实现消息传递机制的代码基本上都在文件ipcmsg.c中,消息队列的主要调用有下面4个(1)msgget:调用者提供一个消息队列的键标(用于表示个消息队列的唯一名字),当这个消息队列存在的时候,这个消息调用负责返回这个队列的标识号;如果这个队列不存在,就创建一个消息队列,然后返回这个消息队列的标识号,主要由sys_msgget执行。(2)msgsnd:向一个消息队列发送一个消息,主要由sys_msgsnd执行。(3)msgrcv:从一个消息队列中收到一个消息,主要由sys_msgrcv执行。(4)msgctl:在消息队列上
5、执行指定的操作。根据参数的不同和权限的不同,可以执行检索、删除等的操作,主要由sys_msgctl执行。#include#include#includeintmsgget(key_tmsgkey,intflag);取得一个消息队列的ID,如不存在则建立。返回值:成功时:消息队列的ID失败时:-1intmsgsnd(intmsqid,structmsgbuf*msgp,size_tmsgsiz,intmsgflag);向消息队列送消息返回值:成功时:0失败时:-1msqid是消息队列的ID,size_tmsgsiz是结构体成员mdata的大小,msgflag与上一章所讲的共享内存的flag起一样
6、的作用,不过,当这个参数为IPC_NOWAIT的时候,如果消息队列已满,则返回错误值。如果不为IPC_NOWAIT,在消息队列已满的情况下,会一直等到消息队列有空地方的时候再发送。注意这里的这个structmsgbuf*msgp。要求的格式如下:structmsgbuflongmtype;charmdata256;longmtype在这里我们用来保存本进程的PID。mdata则是保存要发送的数据。由于mdata的大小不一定(根据实际需要定义),所以这个结构体并没有事先定义好。但是我们定义这个结构体的时候一定要遵循这个规定。你可以改的,只有mdata的大小,和结构体的名称。尽量不要修改结构体成员
7、的名称和类型。实际上,根据mtype,我们还可以有所选择地接受消息。这在下面将会谈到。intmsgrcv(intmsqid,structmsgbuf*msgp,size_tmsgsiz,longmsgtyp,intmsgflag);从消息队列取得一个消息返回值:成功时:0失败时:-1msqid,*msgp,msgsiz不用说了。longmsgtyp是结构体msgbuf的mtype成员。msgflag与上述一样。只不过为IPC_NOWAIT的时候,如果消息队列是空的,则等到有消息可读的时候再读。当不为IPC_NOWAIT的时候,如果消息队列是空的,则返回错误值(与字面上理解的有些相反)下面这个链
8、接帮助了我更好地理解了msgrcv 中的 long msgtyp这个参数和structmsgbuflongmtype;charmdata256;里的long mtype这个结构体成员。同样地,为了控制管理消息队列,一样有一个函数msgctl()如下:#include#include#includeintmsgctl(intmsqid,intcmd,structmsqid_ds*buf);返回值:成功时:0失败时:-1cmd所指定的值与共享内存部分相同。最后自己写了一个利用消息队列实现进程通信基本思路:我每次将A端发送消息时的消息类型标记为奇数,将B端发送的消息类型为偶数。A端读取消息类型为偶数
9、的消息(也就是说是从B端发送过来的)B端读取消息类型为奇数的消息(也就是说是从A端发送过来的)A.c和B.c 程序基本上是一样的 这个程序还有一些不完善的地方:1.每个端口不能连续输入,必须等对方输入以后才 会显示结果。这里我也不清楚怎么回事。gdb的调试还不太会,错误不太会找。希望高手指教,呵呵2.没有删除消息队列,下次打开时候还会残留以前的消息最后列出参考资料:Linux软件工程师(c语言)实用版linux消息队列操作 分类: linux 2008-03-11 23:32 31857人阅读 评论(10) 收藏 举报 linuxstructbufferfile存储cmd对消息队列的操作无非有
10、下面三种类型:1、 打开或创建消息队列消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,只需提供该消息队列的键值即可;注:消息队列描述字是由在系统范围内唯一的键值生成的,而键值可以看作对应系统内的一条路经。2、 读写操作消息读写操作非常简单,对开发人员来说,每个消息都类似如下的数据结构:struct msgbuflong mtype;char mtext1;mtype成员代表消息类型,从消息队列中读取消息的一个重要依据就是消息的类型;mtext是消息内容,当然长度不一定为1。因此,对于发送消息来说,首先预置一个msgbuf缓冲区并写入消息类型和
11、内容,调用相应的发送函数即可;对读取消息来说,首先分配这样一个msgbuf缓冲区,然后把消息读入该缓冲区即可。3、 获得或设置消息队列属性:消息队列的信息基本上都保存在消息队列头中,因此,可以分配一个类似于消息队列头的结构(struct msqid_ds,见附录 2),来返回消息队列的属性;同样可以设置该数据结构。消息队列API1、文件名到键值#include #include key_t ftok (char*pathname, char proj);它返回与路径pathname相对应的一个键值。该函数不直接对消息队列操作,但在调用ipc(MSGGET,)或msgget()来获得消息队列描述
12、字前,往往要调用该函数。典型的调用代码是: key=ftok(path_ptr, a); ipc_id=ipc(MSGGET, (int)key, flags,0,NULL,0); 2.系统V消息队列API系统V消息队列API共有四个,使用时需要包括几个头文件:#include #include #include 1)int msgget(key_t key, int msgflg)参数key是一个键值,由ftok获得;msgflg参数是一些标志位。该调用返回与健值key相对应的消息队列描述字。在以下两种情况下,该调用将创建一个新的消息队列: 如果没有消息队列与健值key相对应,并且msgfl
13、g中包含了IPC_CREAT标志位; key参数为IPC_PRIVATE; 参数msgflg可以为以下:IPC_CREAT、IPC_EXCL、IPC_NOWAIT或三者的或结果。调用返回:成功返回消息队列描述字,否则返回-1。注:参数key设置成常数IPC_PRIVATE并不意味着其他进程不能访问该消息队列,只意味着即将创建新的消息队列。2)int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);该系统调用从msgid代表的消息队列中读取一个消息,并把消息存储在msgp指向的msgbuf结构中
14、。msqid为消息队列描述字;消息返回后存储在msgp指向的地址,msgsz指定msgbuf的mtext成员的长度(即消息内容的长度),msgtyp为请求读取的消息类型;读消息标志msgflg可以为以下几个常值的或: IPC_NOWAIT 如果没有满足条件的消息,调用立即返回,此时,errno=ENOMSG IPC_EXCEPT 与msgtyp0配合使用,返回队列中第一个类型不为msgtyp的消息 IPC_NOERROR 如果队列中满足条件的消息内容大于所请求的msgsz字节,则把该消息截断,截断部分将丢失。 msgrcv手册中详细给出了消息类型取不同值时(0; 0; =0),调用将返回消息队
15、列中的哪个消息。msgrcv()解除阻塞的条件有三个:1. 消息队列中有了满足条件的消息; 2. msqid代表的消息队列被删除; 3. 调用msgrcv()的进程被信号中断; 调用返回:成功返回读出消息的实际字节数,否则返回-1。3)int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);向msgid代表的消息队列发送一个消息,即将发送的消息存储在msgp指向的msgbuf结构中,消息的大小由msgze指定。对发送消息来说,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,
16、msgsnd是否等待。造成msgsnd()等待的条件有两种: 当前消息的大小与当前消息队列中的字节数之和超过了消息队列的总容量; 当前消息队列的消息数(单位个)不小于消息队列的总容量(单位字节数),此时,虽然消息队列中的消息数目很多,但基本上都只有一个字节。 msgsnd()解除阻塞的条件有三个: 1. 不满足上述两个条件,即消息队列中有容纳该消息的空间; 2. msqid代表的消息队列被删除; 3. 调用msgsnd()的进程被信号中断; 调用返回:成功返回0,否则返回-1。4)int msgctl(int msqid, int cmd, struct msqid_ds *buf);该系统调
17、用对由msqid标识的消息队列执行cmd操作,共有三种cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。1. IPC_STAT:该命令用来获取消息队列信息,返回的信息存贮在buf指向的msqid结构中; 2. IPC_SET:该命令用来设置消息队列的属性,要设置的属性存储在buf指向的msqid结构中;可设置属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes,同时,也影响msg_ctime成员。 3. IPC_RMID:删除msqid标识的消息队列; 调用返回:成功返回0,否则返回-1。-/*msgserver.c*
18、/#include #include #include #include #include #include #include #define MSG_FILE msgserver.c #define BUFFER 255 #define PERM S_IRUSR|S_IWUSR /* 服务端创建的消息队列最后没有删除,我们要使用ipcrm命令来删除的 */* ipcrm -q */struct msgtype long mtype; char bufferBUFFER+1; ; int main() struct msgtype msg; key_t key; int msgid; if(k
19、ey=ftok(MSG_FILE,a)=-1) fprintf(stderr,Creat Key Error:%s/n, strerror(errno); exit(1); if(msgid=msgget(key, PERM|IPC_CREAT|IPC_EXCL)=-1) fprintf(stderr, Creat Message Error:%s/n, strerror(errno); exit(1); printf(msqid = %d/n, msgid); while(1) msgrcv(msgid, &msg, sizeof(struct msgtype), 1, 0); fprint
20、f(stderr,Server Receive:%s/n, msg.buffer); msg.mtype = 2; msgsnd(msgid, &msg, sizeof(struct msgtype), 0); exit(0); /* msgclient.c */#include #include #include #include #include #include #include #include #define MSG_FILE msgserver.c #define BUFFER 255 #define PERM S_IRUSR|S_IWUSR struct msgtype long
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 消息 队列 进程 通信

限制150内