Linux进程间通信——消息队列
程序员文章站
2022-05-14 08:06:51
...
一句话总结:消息队列也可以独立于发送和接收进程而存在,可以有选择地接收消息;缺点是消息大小有上限。
四大金刚:
1、创建消息队列:int msgget(key_t, key, int msgflg);
2、将消息添加到消息队列中:int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);
3、从消息队列中获取消息:int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);
msgtype 可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。
4、操作消息队列:int msgctl(int msgid, int command, struct msgid_ds *buf);
command是将要采取的动作,它可以取3个值,
IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
IPC_RMID:删除消息队列
msgqueue_writer.cpp
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/msg.h>
#define TEST_SIZE 2048
typedef struct msgqueue_st
{
long int msg_type; //作为一个标志,非0:表示可读,0表示可写
char szMsg[TEST_SIZE];
}MsgQueue_st;
int main()
{
int msgid = msgget((key_t)1234, 0666|IPC_CREAT); //失败返回-1,假设成功。
//0666表示权限,与文件一样。如0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。
MsgQueue_st msgQueue;
msgQueue.msg_type = 1; //注意,指定消息类型,必须赋值,否则不通
int i = 0;
while(1)
{
getchar();
snprintf(msgQueue.szMsg, sizeof(msgQueue.szMsg), "hello %d", ++i);
printf("write msg is [%s]\n", msgQueue.szMsg);
msgsnd(msgid, (void*)&msgQueue, sizeof(msgQueue.szMsg), 0); //第三个参数是发送消息的长度
if (5 == i)
{
break;
}
}
return 0;
}
msgqueue_reader.cpp
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/msg.h>
#define TEST_SIZE 2048
typedef struct msgqueue_st
{
long int msg_type; //作为一个标志,非0:表示可读,0表示可写
char szMsg[TEST_SIZE];
}MsgQueue_st;
int main()
{
int msgid = msgget((key_t)1234, 0666|IPC_CREAT); //失败返回-1,假设成功。
//0666表示权限,与文件一样。如0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。
MsgQueue_st msgQueue;
//msgQueue.msg_type = 1; //注意,指定消息类型,必须赋值,否则不通
int i = 0;
while(1)
{
getchar();
msgrcv(msgid, (void*)&msgQueue, sizeof(msgQueue.szMsg), 0, 0); //第三个参数是发送消息的长度
printf("msg from writer is [%s]\n", msgQueue.szMsg);
++i;
if (5 == i)
{
break;
}
}
msgctl(msgid, IPC_RMID, 0); //保证接受完最后一个消息后删除消息队列
return 0;
}
运行结果:
运行读、写程序,查询消息队列,如果读写程序全部终止掉,消息队列还是存在的。
连续5次按下enter键发送数据,此时写数据端运行结束;此时在读数据端按下enter会依次从消息队列中读取数据。