原文链接:进程间通信(IPC)介绍_tangtang_yue的博客-CSDN博客_进程间通信(ipc)介绍
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
1.特点
-
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
-
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
-
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
2.相关API
1 #include <sys/msg.h> 2 // 创建或打开消息队列:成功返回队列ID,失败返回-1 3 int msgget(key_t key, int flag); 4 // 添加消息:成功返回0,失败返回-1 5 int msgsnd(int msqid, const void *ptr, size_t size, int flag); 6 // 读取消息:成功返回消息数据的长度,失败返回-1 7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag); 8 // 控制消息队列:成功返回0,失败返回-1 9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
①创建获取消息队列并且接收消息数据:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main(int argc, char *argv[])
{
int msgId;
struct msgbuf readBuf;
msgId = msgget(0x1234, IPC_CREAT | 0777); //获取创建消息队列,IPC_CREAT后记得加上权限
if (msgId == -1){
printf("get queue failuer!\n");
}
msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888, 0); //0代表进程会一直阻塞直到获取到消息队列信息
printf("read: %s\n", readBuf.mtext);
return 0;
}
②创建获取消息队列并且发送消息数据:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main(int argc, char *argv[])
{
int msgId;
struct msgbuf sendBuf = {888, "this is message from queue"};
msgId = msgget(0x1234, IPC_CREAT | 0777); //获取创建消息队列,IPC_CREAT后记得加上权限
if (msgId == -1){
printf("get queue failuer!\n");
}
msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext), 0);
printf("send over!\n");
return 0;
}
③运行结果:
④接收端实现两个进程相互接发数据内容:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main(int argc, char *argv[])
{
int msgId;
struct msgbuf readBuf;
struct msgbuf sendBuf = {988, "thanks for your sending message"};
//key_t ftok(const char *pathname, int proj_id);
key_t key;
key = ftok(".", 24); //"."代表当前路径,int id一般为8位1-255
printf("key = %x\n", key);
msgId = msgget(key, IPC_CREAT | 0777); //获取创建消息队列,IPC_CREAT后记得加上权限
if (msgId == -1){
printf("get queue failuer!\n");
}
msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 888, 0); //0代表进程会一直阻塞直到获取到消息队列信息
printf("read from queue: %s\n", readBuf.mtext);
msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext), 0);
printf("send successfully!\n");
//int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl(msgId, IPC_RMID, NULL); //为了避免创建获取的消息队列无效堆积,IPC_RIMD参数可以在进程终止后干掉先前的消息队列
return 0;
}
⑤发送端实现两个进程相互接发数据内容:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// int msgget(key_t key, int msgflg);
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
// ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[128]; /* message data */
};
int main(int argc, char *argv[])
{
int msgId;
struct msgbuf readBuf;
struct msgbuf sendBuf = {888, "this is message from queue"};
//key_t ftok(const char *pathname, int proj_id);
key_t key;
key = ftok(".", 24);
printf("key = %x\n", key);
msgId = msgget(key, IPC_CREAT | 0777); //获取创建消息队列,IPC_CREAT后记得加上权限
if (msgId == -1){
printf("get queue failuer!\n");
}
msgsnd(msgId, &sendBuf, sizeof(sendBuf.mtext), 0);
printf("send over!\n");
msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 988, 0);
printf("read from queue: %s\n", readBuf.mtext);
//int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgctl(msgId, IPC_RMID, NULL); //通过msgctl函数控制消息队列,IPC_RMID参数将消息队列干掉,第三个参数一般为NULL
return 0;
}
⑥运行结果:
PS:在获取创建消息队列时,消息队列ID既可以手动输入十六进制数给定,也可以通过ftok()函数自动获取,其相关介绍如下:
key_t ftok( const char * fname, int id )
fname就是你指定的文件名(已经存在的文件名),一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。
id是子序号。虽然是int类型,但是只使用8bits(1-255)。
在一般的UNIX实现中,是将文件的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文件的索引节点号为65538,换算成16进制为0x010002,而你指定的ID值为38,换算成16进制为0x26,则最后的key_t返回值为0x26010002。
另外msgctl()用法:int msgctl(int msqid, int cmd, struct msqid_ds *buf)
msgctl(msgId, IPC_RMID, NULL)。为了避免创建获取的消息队列无效堆积,IPC_RIMD参数可以在进程终止后干掉先前的消息队列