Linux进程通信之消息队列
消息队列主要由下面四个函数组成
1、msgget
2、msgctl
3、msgsnd
3、msgrcv
1、msgget
得到消息队列标识符或创建一个消息队列对象并返回消息队列标识符
- 函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg)
- 函数参数
key: 跟上一篇讲的共享内存一样
msgflag:跟上一篇的一样。
注意:这里少了一个size参数
- 返回值
成功:返回消息队列的标识符
出错:-1
- 代码
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, char **argv){
int msgid;
int key;
key = ftok("./a.c",'a');
msgid = msgget(key, IPC_CREAT | 777);
if(msgid <0){
printf("create msg queue failes:[%s]\n",strerror(errno));
return -1;
}
printf("create msgaqu is successfuli:[%d]\n",msgid);
system("ipcs -q");
return 0;
}
2、msgctl
获取、设置消息队列的属性,即删除消息队列
- 函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf)
- 函数参数
跟共享内存的一样,这里就不多说了
- 返回值
成功:0
出错:-1
- 代码
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int main(int argc, char **argv){
int msgid;
int key;
key = ftok("./a.c",'a');
msgid = msgget(key, IPC_CREAT | 777);
if(msgid <0){
printf("create msg queue failes:[%s]\n",strerror(errno));
return -1;
}
printf("create msgaqu is successfuli:[%d]\n",msgid);
system("ipcs -q");
//删除内核中消息队列
msgctl(msgid,IPC_RMID,NULL);
system("ipcs -q");
return 0;
}
3、msgsnd
将msgp消息写入到标识符为msqid的消息队列
- 函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)
- 函数参数
msgid : 消息队列标识符
msgp : 发送给队列的消息。一般为结构体,如下:
struct msg_form {
long mtype; //消息类型
char mtext[256]; //消息内容
};
msgsz : 要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度
msgflg : 三种情况如下
0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列
IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回
IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。
- 返回值
成功:0
失败:-1
- 代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <unistd.h>
// 用于创建一个唯一的key
#define MSG_FILE "/etc/passwd"
// 消息结构
struct msg_form {
long mtype;
char mtext[256];
};
int main()
{
int msqid;
key_t key;
struct msg_form msg;
// 获取key值
if((key = ftok(MSG_FILE,'z')) < 0)
{
perror("ftok error");
exit(1);
}
// 打印key值
printf("Message Queue - Server key is: %d.\n", key);
// 创建消息队列
if ((msqid = msgget(key, IPC_CREAT|0777)) == -1)
{
perror("msgget error");
exit(1);
}
// 打印消息队列ID及进程ID
printf("My msqid is: %d.\n", msqid);
printf("My pid is: %d.\n", getpid());
// 循环读取消息
for(;;)
{
msgrcv(msqid, &msg, 256, 888, 0);// 返回类型为888的第一个消息
printf("Server: receive msg.mtext is: %s.\n", msg.mtext);
printf("Server: receive msg.mtype is: %ld.\n", msg.mtype);
msg.mtype = 999; // 客户端接收的消息类型
sprintf(msg.mtext, "hello, I'm server %d", getpid());
msgsnd(msqid, &msg, sizeof(msg.mtext), 0);
}
return 0;
}
4、msgrcv
从标识符为msqid的消息队列读取消息并存于msgp中,读取后把此消息从消息队列中删除
- 函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msgid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
- 函数参数
msgid : 消息队列标识符
msgp : 存放消息的结构体,结构体类型要与msgsnd函数发送的类型相同
msgsz : 要接收消息的大小,不含消息类型占用的4个字节
msgtyp : 有三种情况
0:接收第一个消息
>0:接收类型等于msgtyp的第一个消息
<0:接收类型等于或者小于msgtyp绝对值的第一个消息
msgflg : 有四种情况
0: 阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待
IPC_NOWAIT:如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG
IPC_EXCEPT:与msgtype配合使用返回队列中第一个类型不为msgtype的消息
IPC_NOERROR:如果队列中满足条件的消息内容大于所请求的size字节,则把该消息截断,截断部分将被丢弃
- 代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <unistd.h>
// 用于创建一个唯一的key
#define MSG_FILE "/etc/passwd"
// 消息结构
struct msg_form {
long mtype;
char mtext[256];
};
int main()
{
int msqid;
key_t key;
struct msg_form msg;
// 获取key值
if ((key = ftok(MSG_FILE, 'z')) < 0)
{
perror("ftok error");
exit(1);
}
// 打印key值
printf("Message Queue - Client key is: %d.\n", key);
// 打开消息队列
if ((msqid = msgget(key, IPC_CREAT|0777)) == -1)
{
perror("msgget error");
exit(1);
}
// 打印消息队列ID及进程ID
printf("My msqid is: %d.\n", msqid);
printf("My pid is: %d.\n", getpid());
// 添加消息,类型为888
msg.mtype = 888;
sprintf(msg.mtext, "hello, I'm client %d", getpid());
msgsnd(msqid, &msg, sizeof(msg.mtext), 0);
// 读取类型为777的消息,ipc_nowait表示非阻塞,0是阻塞
msgrcv(msqid, &msg, 256, 777, IPC_NOWAIT);
printf("Client: receive msg.mtext is: %s.\n", msg.mtext);
printf("Client: receive msg.mtype is: %ld.\n", msg.mtype);
return 0;
}