内核中的System V消息队列用一个消息队列标识符表示,每个消息队列维护一个结构体(如图)

进程通信(4):System V消息队列_操作系统

消息队列可以类似画成一个链 表。

每个消息由类型,长度和数据组成。

msgget函数通过key(由ftok函数或者IPC_PRIVATE创建)创建一个新的消息队列。

进程通信(4):System V消息队列_服务器_02

打开消息队列后,msgsnd向消息队列发送数据。

进程通信(4):System V消息队列_操作系统_03

msqid是消息队列表示符,ptr是一个结构指针,指向消息。

进程通信(4):System V消息队列_操作系统_04

也可以是自定义的消息结构。Flag可以设置消息队列为非阻塞。

使用msgrcv函数可以从某个消息队列中读出一个消息。

进程通信(4):System V消息队列_消息队列_05

msqid消息队列表示符,ptr接收缓冲区,length数据部分长度,type读出消息的类型,flag可以设置非阻塞读。

type=0,返回队列第一个消息,type>0,返回类型值为type的第一个消息,type<0返回类型值小于等于type参数的绝对值消息中类型最小的第一个消息。

msgctl控制消息队列,可以删除指定的消息队列,或者设置消息队列的属性。

例1:使用两个消息队列实现两个进程的通信。

一个消息队列用来从A发给B,B读取A。

另一个消息队列用来B发给A,A读取B。

进程通信(4):System V消息队列_消息队列_06

进程通信(4):System V消息队列_消息队列_07

例2:可以使用一个消息队列实现两个进程的通信。

A发给B类型为n的消息,B读取类型为n的消息。

B发送给A类型为m的消息,A读取类型为m的消息。

例3:使用一个消息队列用于一个服务器和多个客户端通信

进程通信(4):System V消息队列_操作系统_08

约定类型为1的消息是从客户到服务器的,其他所有消息等于客户进程的类型。

客户向服务器的消息队列写自己的pid和路径名,类型为1。

服务器接受类型为1的消息,从中读出Pid和路径名,然后把文件内容发送给消息队列,类型为pid。

例4:每个客户一个消息队列和服务器通信

进程通信(4):System V消息队列_子进程_09

每个客户端使用一个队列,客户给服务器消息队列发送消息,把自己的队列标识符顺便发过去。

服务器收到消息,使用fork创建一个子进程,在子进程中读取文件,把文件内容发送给客户端的消息队列。

(1)需要给SIGCHLD建立信号处理程序。fork出来的子进程不及时回收会成为僵尸进程。进程结束后会向父进程发送SIGCHLD信号,需要手动处理。

(2)fopen需要放在子进程中,这样打开文件阻塞的话,不会阻塞服务器的正常运行。

(3)这样设计的潜在问题是如果某个客户中途死亡,它的私用队列可能永远残留消息。

System V消息队列上使用select和poll

如果想要同时处理网络连接和IPC连接的服务器,会出现问题。IPC描述符和文件描述符不同。

(1)可以让服务器创建一个管道,然后fork一个子进程阻塞在msgrcv调用中。

当有消息时,子进程从队列中读出消息,然后把消息写入管道,让select监听管道描述符的读端(fd[0])。

这样消息被处理的三次。

(2)父进程可以创建一个在它自身和子进程之间分享的共享内存区,然后把把管道用作父子进程间的一种标志。

(这个地方没看懂。)

消息队列限制:

进程通信(4):System V消息队列_子进程_10