进程间通信(2)-消息队列
Linux 中的消息队列是一种进程间通信(IPC)机制,允许不同进程之间通过消息进行通信。
消息队列中的相关函数:
msgget:创建或打开一个消息队列。 函数原型:int msgget(key_t key, int msgflg); 参数: key:消息队列的键值,用于标识消息队列。 msgflg:标志参数,用于指定消息队列的创建方式和权限。 返回值:成功时返回消息队列的标识符(非负整数),失败时返回 -1。 msgctl:对消息队列进行控制。 函数原型:int msgctl(int msqid, int cmd, struct msqid_ds *buf); 参数: msqid:消息队列的标识符。 cmd:控制命令,用于指定执行的操作。 buf:指向 struct msqid_ds 结构的指针,用于传递或接收消息队列的状态信息。 返回值:成功时返回0,失败时返回 -1。 msgsnd:向消息队列发送消息。 函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数: msqid:消息队列的标识符。 msgp:指向要发送的消息的指针。 msgsz:消息的大小(以字节为单位)。 msgflg:标志参数,用于指定发送消息的行为。 返回值:成功时返回0,失败时返回 -1。 msgrcv:从消息队列接收消息。 函数原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); 参数: msqid:消息队列的标识符。 msgp:指向存储接收消息的缓冲区的指针。 msgsz:缓冲区的大小(以字节为单位)。 msgtyp:指定所接收消息的类型。 msgflg:标志参数,用于指定接收消息的行为。 返回值:成功时返回接收到的消息的大小(以字节为单位),失败时返回 -1。
对于ftok补充一点,ftok 函数是一个用于生成 System V IPC(Inter-Process Communication,进程间通信)中键值的函数。在 System V IPC 中,诸如消息队列、共享内存和信号量等资源都需要一个唯一的键值来标识。
ftok 函数的原型如下:
key_t ftok(const char *pathname, int proj_id); 它接受两个参数: pathname:一个指向文件的路径名的指针。通常情况下,你可以选择一个现有的文件,该文件的存在与否对 ftok 函数的结果不会产生影响,因为它只关注文件的索引节点号(inode number)和项目 ID(proj_id)。 proj_id:一个用户定义的整数,用于生成键值的低8位。通常情况下,你可以为不同的 IPC 资源设置不同的项目 ID,以确保它们的键值不冲突。
ftok 函数将 pathname 参数指定的文件的索引节点号和 proj_id 参数合并起来,然后通过一系列位操作生成一个唯一的键值。这个键值将作为 System V IPC 中资源的标识符,用于创建或获取相应的资源。
需要注意的是,ftok 函数的返回值是一个键值 key_t,这个键值会传递给 msgget、shmget 或 semget 等函数,用于创建或获取对应的消息队列、共享内存或信号量。
更多关于ftok函数的解析可见:ftok()函数深度解析
说白了ftok函数就是根据文件生成一个key_t类型的值,key_t一般是一个长整型,那完全可用用一个长整型的数进行替换即可,前提是该长整型数没有作为key_t使用
发送消息的程序msg1.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #define MAX_MSG_SIZE 1024 #define MSG_TYPE 1 // 定义消息结构体 struct msg_buffer { long msg_type; char msg_text[MAX_MSG_SIZE]; }; int main() { int i; int msg_id; key_t key; struct msg_buffer message; // 生成一个唯一的键值 if ((key = ftok("lethe1203", 'B')) == -1) { perror("ftok"); exit(EXIT_FAILURE); } // 创建一个消息队列,如果不存在则创建,否则打开 if ((msg_id = msgget(key, 0666 | IPC_CREAT)) == -1) { // 这里完全可用把key替换为12345678等,去掉"生成一个唯一的键值"的步骤 perror("msgget"); exit(EXIT_FAILURE); } printf("Sending multiple messages to the queue...\n"); // 发送多条消息到队列 for (i = 1; i <= 5; ++i) { // 设置消息的类型为 MSG_TYPE message.msg_type = MSG_TYPE; // 构造消息内容 sprintf(message.msg_text, "This is message %d from sender", i); // 发送消息 if (msgsnd(msg_id, &message, sizeof(message.msg_text), 0) == -1) { perror("msgsnd"); exit(EXIT_FAILURE); } printf("Message %d sent to queue.\n", i); // 为了演示,发送完一条消息后暂停五秒 sleep(5); } printf("All messages sent to the queue.\n"); return 0; }
接收消息的程序msg2.c:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <string.h> #define MAX_MSG_SIZE 1024 #define MSG_TYPE 1 // 定义消息结构体 struct msg_buffer { long msg_type; char msg_text[MAX_MSG_SIZE]; }; int main() { int msg_id; key_t key; struct msg_buffer message; // 生成一个唯一的键值 if ((key = ftok("lethe1203", 'B')) == -1) { perror("ftok"); exit(EXIT_FAILURE); } // 获取现有的消息队列,如果不存在则创建 if ((msg_id = msgget(key, 0666 | IPC_CREAT)) == -1) { // 这里完全可用把key替换为12345678等,去掉"生成一个唯一的键值"的步骤 perror("msgget"); exit(EXIT_FAILURE); } printf("Receiving messages from the queue...\n"); // 从队列中接收消息 while (1) { // 接收消息 if (msgrcv(msg_id, &message, sizeof(message.msg_text), MSG_TYPE, 0) == -1) { perror("msgrcv"); exit(EXIT_FAILURE); } // 打印接收到的消息 printf("Message received: %s\n", message.msg_text); } return 0; }