一.关于消息队列的概念:
1.消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法 ;
2.每个数据块都被认为有一个数据类型, 接收者进程接收的数据可以有不同类型的数据 ;
3.消息队列也有管道一样的不足, 就是每个消息的最大长度是有上限的(MSGMAX), 每个消息队列的总的字节数是有上限的(MSGMNB), 系统上消息队列的总数也有一个上限(MSGMNI) ;
4.进程通信,消息队列的生命周期随内核 ;
5.IPC资源用完必须删除完;
二.IPC对象结构:
struct ipc_perm
{
key_t __key; //消息队列里唯一的标示符
uid_t uid;
gid_t gid;
uid_t cuid;
unsigned short mode;//消息队列的权限
unsigned short __seq;
}
三.关于消息队列的函数:
1.创建函数:
int msgget(key_t key, int msgflg);
参数:
key:消息队列中的唯一的那个标示符
msgflg:一般是由IPC_CREAT和IPC_EXCL设置;
当IPC_CREAT 和 IPC_EXCL 都设置的时候代表的是如果没有消息队列,则创建一个新的消息队列,返回这个新的消息队列的标识符, 如果已经有消息队列,则出错返回;当只设置IPC_CREAT的时候,如果没有消息队列则创建一个消息队列并且返回创建的消息队列的标识符,如果已经有消息队列,则返回原来已有的消息队列标识符;
返回值:成功:非负数; 失败:返回0;
2.产生消息队列标识符的函数:
key_t ftok(const char* pathnaem, int project_id);
其中pathname和project_id都是有用户自己设定的
返回值:成功:返回key值; 失败:返回-1;
3.消息队列的控制函数:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msqid:msgget函数返回的标识码;
cmd:将要采取的动作(IPC_STAT将nsqid_ds结构中的数据设置为消息队列的当前关联值; IPC_SET 进程有足够权限时,把消息队列的当前关联值设置为msqid_ds 数据结构中给定的值; IPC_RMID 是删除消息队列)
4.消息队列的发送:
int msgsnd(int msqid, const void* msgq, size_t msgsz, int msgflag);
msqid:msgget函数返回的标识码,
msgq 是一个指向准备发送消息的一个指针;
msgsz 是发送的消息的长度,这个长度不包括消息类型的长度;
5.消息的接收:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msqtyp, int msgflg);
msqid:由msgget返回的标识码;
msgp:指向接收消息的一个指针;
msqtyp: 实现接收优先级;
msgflg: 一般设置为0;
四.代码实现如下所示:
//common.h
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#define PATHNAME "."
#define PROJ_ID 0x6666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
struct msgbuf
{
long mtype;
char mtext[1024];
};
int CreateMsgQueue();
int GetMsgQueue();
int DestroyMsgQueue(int msgid);
int SendMsg(int msgid, int who, char* msg);
int RecvMsg(int msgid, int recv_type, char out[]);
#endif //__COMM_H__
//comm.c
#include"comm.h"
int main()
{
int msgid = GetMsgQueue();
char buf[1024];
while(1)
{
buf[0] = 0;
printf("Please Enter# ");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf));
if(s > 0)
{
buf[s - 1] = 0;
SendMsg(msgid, CLIENT_TYPE, buf);
printf("send done, wait...\n");
}
RecvMsg(msgid, SERVER_TYPE, buf);
if(strcmp(buf, "quit") == 0)
{
printf("Server quit, me too!\n");
break;
}
printf("client say# %s\n", buf);
}
return 0;
}
//client.c
#include"comm.h"
int main()
{
int msgid = GetMsgQueue();
char buf[1024];
while(1)
{
buf[0] = 0;
printf("Please Enter# ");
fflush(stdout);
ssize_t s = read(0, buf, sizeof(buf));
if(s > 0)
{
buf[s - 1] = 0;
SendMsg(msgid, CLIENT_TYPE, buf);
printf("send done, wait...\n");
}
RecvMsg(msgid, SERVER_TYPE, buf);
if(strcmp(buf, "quit") == 0)
{
printf("Server quit, me too!\n");
break;
}
printf("client say# %s\n", buf);
}
return 0;
}
//server.c
#include"comm.h"
int main()
{
int msgid = CreateMsgQueue();
char buf[1024];
while(1)
{
buf[0] = 0;
RecvMsg(msgid, CLIENT_TYPE, buf);
if(strcmp(buf, "quit") == 0)
{
printf("Client quit, me too!\n");
break;
}
printf("Client say# %s\n", buf);
printf("Please Enter# ");
fflush(stdout);
int s = read(0, buf, sizeof(buf));
buf[s - 1] = 0;
SendMsg(msgid, SERVER_TYPE, buf);
printf("send done, wait recv...\n");
}
DestroyMsgQueue(msgid);
return 0;
}
补充:关于消息队列的相关操作:
ipcs 查看IPC:
-m 查看共享内存
-s 查看信号量
-q 查看消息队列
ipcrm 删除IPC: