使用 System V message queue 实现进程间通信

作者:

被问到“Linux上用什么命令删除一个MQ”. 为了验证这个问题需要先整出来一个MQ,然后删除它。

相关系统调用

[cc lang=”C”]
// ftok(): convert a pathname and a project identifier to a System V IPC key.
#include
#include

key_t ftok(const char *pathname, int proj_id);
[/cc]

[cc lang=”C”]
// msgget(): either returns the message queue identifier for a newly created message queue or returns the identifiers for a queue which exists with the same key value.
#include
#include
#include

int msgget(key_t key, int msgflg);
[/cc]

[cc lang=”C”]
// msgsnd(): Data is placed on to a message queue by calling msgsnd().
// msgrcv(): messages are retrieved from a queue.
#include
#include
#include

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);
[/cc]

[cc lang=”C”]
// msgctl(): It performs various operations on a queue. Generally it is use to destroy message queue.
#include
#include
#include

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
[/cc]

Writer – 往MQ里写入消息

代码是从网上抄的[1],挺好用。
[cc lang=”C”]
// C Program for Message Queue (Writer Process)
#include
#include
#include

// structure for message queue
struct mesg_buffer {
long mesg_type;
char mesg_text[100];
} message;

int main()
{
key_t key;
int msgid;

// ftok to generate unique key
// 每个程序都可以用相同的 pathname 和 proj_id 来获取相同的 key.
key = ftok(“progfile”, 65);

// msgget creates a message queue
// and returns identifier
msgid = msgget(key, 0666 | IPC_CREAT);
message.mesg_type = 1;

// 获取用户输入
printf(“Write Data : “);
gets(message.mesg_text);

// msgsnd to send message
msgsnd(msgid, &message, sizeof(message), 0);

// display the message
printf(“Data send is : %s \n”, message.mesg_text);

return 0;
}
[/cc]

Reader – 从MQ中读取消息

[cc lang=”C”]
// C Program for Message Queue (Reader Process)
#include
#include
#include

// structure for message queue
struct mesg_buffer {
long mesg_type;
char mesg_text[100];
} message;

int main()
{
key_t key;
int msgid;

// ftok to generate unique key
// 使用跟 writer 相同的 pathname 和 proj_id 来获取 key.
key = ftok(“progfile”, 65);

// msgget creates a message queue
// and returns identifier
msgid = msgget(key, 0666 | IPC_CREAT);

// msgrcv to receive message
msgrcv(msgid, &message, sizeof(message), 1, 0);

// display the message
printf(“Data Received is : %s \n”,
message.mesg_text);

// to destroy the message queue
msgctl(msgid, IPC_RMID, NULL);

return 0;
}
[/cc]

测试验证

运行 writer 往 mq 写信息,reader 可以接收到这个信息。
[cc lang=”text”]
# echo “test message” | ./writer
Write Data : Data send is : test message
# ./reader
Data Received is : test message
[/cc]

从 writer 的 strace 可以看到,它调用了 msgget() 和 msgsnd() 两个 system call.
[cc lang=”text”]
stat(“progfile”, 0x7ffe6e4f1560) = -1 ENOENT (No such file or directory)
msgget(0xffffffff, IPC_CREAT|0666) = 32768
msgsnd(32768, {1, “haha\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0″…}, 112, 0) = 0
[/cc]

从 reader 的 strace 可以看到,它调用了 msgget() 和 msgrcv() 来获取数据,调用 msgctl() 来删除这个 queue.
[cc lang=”text”]
stat(“progfile”, 0x7fff6b97ea70) = -1 ENOENT (No such file or directory)
msgget(0xffffffff, IPC_CREAT|0666) = 98304
msgrcv(98304, {1, “haha\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0″…}, 112, 1, 0) = 112
msgctl(98304, IPC_RMID, NULL) = 0
[/cc]

删除一个MQ

好了,终于可以尝试手动删除MQ了。从上面可以知道,如果没有任何一个程序调用 msgctl() 来删除一个MQ,而所有用这个MQ的程序都退出了,这个MQ的记录就一直存在于内存里了。

[cc lang=”text”]
# ipcs

—— Message Queues ——–
key msqid owner perms used-bytes messages
0xffffffff 0 root 666 112 1

—— Shared Memory Segments ——–
key shmid owner perms bytes nattch status

—— Semaphore Arrays ——–
key semid owner perms nsems
[/cc]

用 ipcrm -q 命令可以删除这个 queue.
[cc lang=”text”]
# ipcrm -q 0
[/cc]

从 strace 中也能看到,它其实也是调用 msgctl().
[cc lang=”text”]
msgctl(163840, IPC_RMID, NULL) = 0
[/cc]

MQ属于什么内存类型?

看到我写这文章,同事补了个问题,这些 Message Queue 算是什么类型的内存? 匿名页还是共享页?

我觉得是共享页,先挖坑,后面再举证。

参考

[1] https://www.geeksforgeeks.org/ipc-using-message-queues/
[2] https://stackoverflow.com/questions/3056307/how-do-i-use-mqueue-in-a-c-program-on-a-linux-based-system
[3] Chapter 15, Advanced Programming in the UNIX Environment 3rd Edition