进程间通信之System V消息队列(二)-msgsnd,msgrcv

接着上一篇文章的内容总结,上一篇文章总结了消息队列函数中的前两个msgget函数和msgctl函数,接下来学习总结msgsnd函数和msgrcv函数。

1.msgsnd函数
  • 功能:把一条消息添加到消息队列中
  • 原型:
    int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
  • 参数:
    • msqid:由msgget函数返回的消息队列标识码
    • msgp:是一个指针,指向准备发送的消息
    • msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
    • msgflg:控制着当前消息队列满或到达系统上限时将要发生的事情
  • 返回值:成功返回0;失败返回-1

(1)msgflg=IPC_NOWAIT表示队列满不等待,返回EAGAIN错误

(2)消息结构在两方面受到制约。首先,它必须小于系统规定的上限值(MSGMAX);其次,它必须以一个long int长整数开始,接收者函数利用这个长整数确定消息的类型

(3)消息结构参考形式如下:

(4)考虑如下示例:
1)接受三个参数,第二个参数为发送消息的长度msgsz;第三个参数为消息类型mtype。
2)调用msget函数打开消息队列,并定义一个消息结构体struct msgbuf *ptr,令ptr->mtype指向type。最后调用msgsnd函数:
msgsnd(msgid, ptr, len, 0);

3)编译后,发送一个长度为100字节,类型为1的消息到消息队列:

查看结果可知,消息队列中字节大小为100,消息个数为1(因为我们只发送了一次消息到消息队列,这里的1跟消息类型1不同)。

2.msgrcv函数
  • 功能:从一个消息队列接受消息
  • 原型:
    ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtype, int msgflg);
  • 参数:
    • msqid:由msgget函数返回的消息队列标识码
    • msgp:是一个指针,指针指向准备接收的消息
    • msgsz:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int长整型
    • msgtype:它可以实现接收优先级的简单形式
    • msgflg:控制着队列中没有相应类型的消息可供接收时将要发生的事
  • 返回值:成功返回实际放到接收缓冲区里的字符个数;失败返回-1

其中,对msgtype有:

  • msgtype=0:返回队列第一条消息,即按顺序接收
  • msgtype>0:返回队列第一条类型等于msgtype的消息
  • msgtype<0:返回队列第一条类型小于等于msgtype绝对值的消息
  • msgflg=IPC_NOWAIT:队列没有可读消息不等待,返回ENOMSG错误
  • msgflg=MSG_NOERROR:消息大小超过msgsz时被截断
  • msgtype>0且msgflg=MSG_EXCEPT:接受类型不等于msgtype的第一条消息

(1)考虑如下示例

其中使用了getopt函数,当指定-n选项时,即意味着flag增加了IPC_NOWAIT选项;-t选型后可接消息的类型。

1)编译运行,接收消息类型为1的消息:

2)不指定消息类型,则type=0,按顺序接收队列中的消息

3)指定-n选项,以非阻塞的方式接收消息,比如接收一个类型不存在的消息,就会阻塞,此时若指定-n,则不会阻塞:

(2)由上示例可知,消息队列可以按照指定的方式来接收消息,而不用像管道一样按着先进先出的顺序进行接收。

3.消息队列实现回射客户/服务器

首先看如下实现方案:消息队列回射服务器

(1)该模型中,我们只用到了一个队列,它既可以保存从客户到服务器端的消息,也可以保存从服务器到客户端的消息。达到了队列的复用,并且可以用于双向通信。

(2)那么服务器端如何区分消息是发送给不同的客户端的呢?这里我们可以使用类型来进行区分,给不同的客户端发送的消息是不同类型的消息。所以客户端接收的时候,只需接收对应类型的消息即可。

(3)那么又该用什么来表示这些客户端的类型呢?这里我们使用客户端进程PID来表示客户端的类型。

(4)还有一个问题,服务器端怎么获知客户端的进程PID(即客户端类型)呢?可以这么解决,所有客户端给服务器发送的消息的类型都置为1,并且其发送的数据要包括两项内容:一项为客户端进程PID,另一项则为需要发送的数据。

具体实现如下:

服务端:
1)首先创建一个众所周知的键——即消息队列1234,然后调用echo_srv;
2)echo_srv中,不断接受类型为1的消息:
n = msgrcv(msgid, &msg, MSGMAX, 1, 0);

客户端:

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注