消息队列(Message Queue):是消息的链表,存放在内核中并由消息队列标识符标识
- 优点:可以实现任意进程间的通信,并通过系统调用函数来实现消息发送和接收之间的同步,无需考虑同步问题,方便
- 缺点:信息的复制需要额外消耗 CPU 的时间,不适宜于信息量大或操作频繁的场合
消息队列提供了一个从一个进程向另一个进程发送数据块的方法,每个数据块都可以被认为是有一个类型,接收者接受的数据块可以有不同的类型。
消息队列函数:
1、msgget
功能:创建和访问一个消息队列
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflag);
参数:
key:消息队列名称,用ftok()产生
msgflag:IPC_CREAT或者IPC_EXCL,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。
返回值:成功返回非负整数,即消息队列的标识码,失败返回-1
2、ftok
功能:创建消息队列名称
原型:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
返回值:成功返回一个key值,用于创建消息队列,失败返回-1
3、msgctl
功能:消息队列的控制函数
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
mgqid:由msgget函数返回的消息队列标识
cmd:命令,这边有三个命令
- IPC_STAT把msqid_ds结构中的数据设置为消息队列的当前关联值
- IPC_SET在进程有足够权限的前提下,把消息队列的当前值设置为msqid_ds数据结构中给出的值
- IPC_RMID删除消息队列
返回值:成功返回0,失败返回-1
4、msgsnd
功能:把一条消息添加到消息队列中
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msgid:msgget函数返回的消息队列标识码
msgp:指针指向准备发送的消息
msgsz:msgp指向的消息的长度
msgflg:默认为0
返回值:成功返回0,失败返回-1
发送的消息结构:
struct msgbuf
{
long mtye;
char mtext[1];
};
5、msgrcv
功能:从一个消息队列接收消息
原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:
msgid:msgget函数返回的消息队列标识码
msgp:指针指向准备发送的消息
msgsz:msgp指向的消息的长度
msgtyp:消息类型
- type==0,返回队列中第一个消息
- type > 0, 返回队列中消息类型为type的第一个消息
- type < 0, 返回队列中消息类型值小于或等于type绝对值的消息,如果这种消息有若干个,则取类型值最小的消息
msgflg:默认为0
comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
struct msgbuf
{
long mtype;
char mtext[1024];
};
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
int createMsgQueue();
int getMsgQueue();
int destoryMsgQueue(int msg_id);
int sendMsgQueue(int msg_id, int who, char *msg);
int recvMsgQueue(int msg_id, int recvType, char out[]);
#endif
comm.c
#include "comm.h"
static int commMsgQueue(int cmd)
{
key_t key = ftok("/tmp", 0x6666);
if(key < 0)
{
perror("ftok");
return -1;
}
int msg_id = msgget(key, cmd);
if(msg_id < 0)
{
perror("msgget");
}
return msg_id;
}
int createMsgQueue()
{
return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}
int getMsgQueue()
{
return commMsgQueue(IPC_CREAT);
}
int destoryMsgQueue(int msg_id)
{
if(msgctl(msg_id, IPC_RMID, NULL) < 0)
{
perror("msgctl");
return -1;
}
return 0;
}
int sendMsgQueue(int msg_id, int type, char *msg)
{
struct msgbuf buf;
buf.mtype = type;
strcpy(buf.mtext, msg);
if(msgsnd(msg_id, (void*)&buf, sizeof(buf.mtext), 0) < 0)
{
perror("msgsnd");
return -1;
}
return 0;
}
int recvMsgQueue(int msg_id, int recvType, char out[])
{
struct msgbuf buf;
int size = sizeof(buf.mtext);
if(msgrcv(msg_id, (void *)&buf, size, recvType, 0) < 0)
{
perror("msgrcv");
return -1;
}
strncpy(out, buf.mtext, size);
out[size] = 0;
return 0;
}
server.c
#include "comm.h"
int main()
{
int msgid = createMsgQueue();
printf("msgid = %d\n", msgid);
char buf[1024] = {0};
while(1)
{
recvMsgQueue(msgid, CLIENT_TYPE, buf);
if(strcasecmp("quit", buf) == 0)
break;
printf("client:%s\n", buf);
/*
printf("Please enter:");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf));
if(s > 0)
{
buf[s - 1] = 0;
sendMsgQueue(msgid, SERVER_TYPE, buf);
printf("send done, wait recv...\n");
}
*/
}
destoryMsgQueue(msgid);
return 0;
}
client.c
#include "comm.h"
int main()
{
int msgid = getMsgQueue();
printf("msgid:%d\n", msgid);
char buf[1024] = {0};
while(1)
{
printf("Please Enter:");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf));
if(s > 0)
{
buf[s - 1] = 0;
sendMsgQueue(msgid, CLIENT_TYPE, buf);
if(strcasecmp("quit", buf) == 0)
break;
//printf("send done, wait recv...\n");
}
//recvMsgQueue(msgid, SERVER_TYPE, buf);
//printf("server#%s\n", buf);
}
return 0;
}
client发送消息:
[root@livedvd tmp]# ./client
msgid:360448
Please Enter:AAAA
Please Enter:BBBBB
Please Enter:HEIIL
Please Enter:quit
[root@livedvd tmp]#
server接收消息:
[root@livedvd tmp]# ./server
msgid = 360448
client:AAAA
client:BBBBB
client:HEIIL
[root@livedvd tmp]#
其中,有两个重要的命令:
ipcs -q :查看IPC资源
ipcrm -q:删除IPC资源
参考:
https://blog.csdn.net/wei_cheng18/article/details/79661495
https://www.cnblogs.com/nufangrensheng/p/3561820.html