消息队列是消息的链接表,存储在内核中,,由消息队列标识符标识。
在linux下查看当前所有的消息队列
ipcs -q
删除一个消息队列
ipcrm -q 消息队列的id
消息队列的特点
内核为每个IPC对象分配的一个结构体
struct ipc_perm
{
__kernel_key_t key;
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode;
unsigned short seq;
};
消息队列的数据结构,每个消息队列有一个结构体用来描述该消息队列。
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message on queue,unused */
struct msg *msg_last; /* last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};
消息队列的几个常用接口函数
用消息队列实现一个简单的服务器/客户端
客户端是主动发送请求。服务器被动接收请求。
服务器先启动,7 x 24小时工作。
客户端发送的请求不同,服务器会根据不同的请求计算不同的结果,并将结果给客户端。
我们首先需要将系统提供的函数进行封装。得到更完整的接口函数,让服务器端和客户端的代码写起来比较简便。
common.h
#pragma once
#include
#include
#include
#include
#include
#define PATHNAME "."
#define PROJ_ID 0x6666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
typedef struct Msgbuf{
long mtype; // 数据的类型
char mtext[1024]; // 存储数据的字符串数组
}Msgbuf;
//创建一个消息队列,如果已经存在,就调用失败
int CreateMsg();
//打开一个已有的消息队列,如果不存在,也返回失败
int GetMsg();
//销毁一个消息队列
int DestroyMsg(int msgid);
int sendMsg(int msgid, long type, char *buf, size_t size);
int recvMsg(int msgid, long type, char *buf, size_t max_size);
common.c
#include "common.h"
#include
#include
#include
#include
int CommonMsg(int flags)
{
key_t key = ftok(PATHNAME, PROJ_ID);
if(key == -1)
{
perror("ftok");
return -1;
}
int msgid = msgget(key, flags);
if(msgid < 0)
{
perror("msgget");
return -1;
}
return msgid;
}
int CreateMsg()
{
// 0666表示权限,所有用户可读可写
//IPC_EXCL要搭配IPC_CREAT使用,意思是要是消息队列不存在就创建, 存在就创建失败。
return CommonMsg(IPC_CREAT | IPC_EXCL | 0666);
}
int GetMsg()
{
return CommonMsg(IPC_CREAT);
}
int DestroyMsg(int msgid)
{
int ret = msgctl(msgid, IPC_RMID, NULL);
if(ret < 0)
{
perror("msgctl");
return -1;
}
return 0;
}
int sendMsg(int msgid, long type, char* buf, size_t size)
{
Msgbuf msgbuf;
if(size >= sizeof(msgbuf.mtext))
{
printf("size is to large!\n");
return -1;
}
msgbuf.mtype = type;
strcpy(msgbuf.mtext, buf);
int ret = msgsnd(msgid, &msgbuf, sizeof(msgbuf.mtext), 0);
if(ret < 0)
{
perror("msgsnd");
return -1;
}
return 0;
}
int recvMsg(int msgid, long type, char *buf, size_t max_size)
{
Msgbuf msgbuf;
ssize_t ret = msgrcv(msgid, &msgbuf, sizeof(msgbuf.mtext), type, 0);
if(ret < 0)
{
perror("msgrcv");
return -1;
}
if(max_size < sizeof(msgbuf.mtext))
{
printf("buf is too small");
return -1;
}
strcpy(buf, msgbuf.mtext);
return 0;
}
服务器端代码
#include
#include
#include "common.h"
int main()
{
int msgid = CreateMsg();
printf("msgid = %d\n", msgid);
while(1)
{
char buf[2048] = {0};
int ret = recvMsg(msgid, CLIENT_TYPE, buf, sizeof(buf) - 1);
if(ret < 0)
{
perror("recvMsg");
return 1;
}
printf("client say: %s",buf);
sendMsg(msgid, CLIENT_TYPE, buf, strlen(buf));
}
//DestroyMsg(msgid);
return 0;
}
客户端
#include
#include
#include "common.h"
int main()
{
int msgid = CreateMsg();
printf("msgid = %d\n", msgid);
while(1)
{
char buf[2048] = {0};
int ret = recvMsg(msgid, CLIENT_TYPE, buf, sizeof(buf) - 1);
if(ret < 0)
{
perror("recvMsg");
return 1;
}
printf("client say: %s",buf);
sendMsg(msgid, CLIENT_TYPE, buf, strlen(buf));
}
//DestroyMsg(msgid);
return 0;
}