消息队列
1. 消息队列介绍
1.1 消息队列概念
消息队列是一种进程间通信或同一进程的不同线程间的通信方式。消息队列是消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
1.2 消息队列特点
- 消息队列是面向消息的,而不是面向字节流的。
- 消息队列可以独立于发送者和接收者存在,从而实现了空间解耦。
- 消息队列提供了一种异步的通信协议,降低了系统的耦合度。
- 消息队列提供了一种缓冲机制,使得消息的发送和接收不必同时发生。
1.3 消息队列优点
- 解耦:允许独立的进程或线程在不需要知道彼此的存在的情况下通信。
- 削峰:接收消息的进程或线程可以以自己的速度来处理消息。
- 管理:消息队列提供了一个可管理的缓冲区,允许发送者发送消息,而不必等待接收者处理。
- 异步通信:消息队列是异步的,发送者不必等待接收者处理消息。
- 灵活性:消息队列提供了灵活性,允许在消息的开始和结束之间插入新的消息。
1.4 消息队列缺点
- 消息队列的实现和维护比较复杂,需要引入新的组件。
- 消息的内容必须事先定义好,接收方必须能够识别消息内容。
- 消息队列的使用增加了系统的复杂性。
1.5 消息队列应用场景
- 两个进程间通信
- 两个线程间通信
- 一个进程中的两个线程间通信
2. 消息队列实现
2.1 消息队列数据结构
消息队列是一个消息链表,每个消息都有一个消息类型,消息类型是一个整数,消息的数据部分可以是任意类型的数据。
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
2.2 消息队列操作
- 创建消息队列:
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); - 控制消息队列:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
2.3 消息队列实例
2.3.1 创建消息队列
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#define MSG_FILE "/etc/passwd"
#define BUFFER 255
struct msg_form {
long mtype;
char mtext[BUFFER];
};
int main()
{
int msqid;
key_t key;
struct msg_form msg;
if ((key = ftok(MSG_FILE, 'z')) < 0) {
perror("ftok error");
exit(1);
}
if ((msqid = msgget(key, IPC_CREAT|0777)) == -1) {
perror("msgget error");
exit(1);
}
printf("Open queue %d\n", msqid);
printf("Please input the message to queue:");
scanf("%s", msg.mtext);
msg.mtype = 888;
if (msgsnd(msqid, &msg, sizeof(msg.mtext), 0) == -1) {
perror("msgsnd error");
exit(1);
}
printf("The message is sent\n");
return 0;
}
2.3.2 接收消息
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#define MSG_FILE "/etc/passwd"
#define BUFFER 255
struct msg_form {
long mtype;
char mtext[BUFFER];
};
int main()
{
int msqid;
key_t key;
struct msg_form msg;
if ((key = ftok(MSG_FILE, 'z')) < 0) {
perror("ftok error");
exit(1);
}
if ((msqid = msgget(key, IPC_CREAT|0777)) == -1) {
perror("msgget error");
exit(1);
}
printf("Open queue %d\n", msqid);
while (1) {
msgrcv(msqid, &msg, BUFFER, 0, 0);
printf("The message from process %ld : %s", msg.mtype, msg.mtext);
}
return 0;
}
2.3.3 控制消息队列
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <string.h>
#define MSG_FILE "/etc/passwd"
#define BUFFER 255
struct msg_form {
long mtype;
char mtext[BUFFER];
};
int main()
{
int msqid;
key_t key;
struct msg_form msg;
if ((key = ftok(MSG_FILE, 'z')) < 0) {
perror("ftok error");
exit(1);
}
if ((msqid = msgget(key, IPC_CREAT|0777)) == -1) {
perror("msgget error");
exit(1);
}
printf("Open queue %d\n", msqid);
msgctl(msqid, IPC_RMID, NULL);
return 0;
}