一、消息队列?
消息队列是个什么东东嘞?它其实就是有点像我们玩的qq啊微信啊什么的,实现彼此之间的消息互发。目前有两种类型的消息队列:POSIX消息队列和System V消息队列。本篇博客学习的是System V消息队列。下面来简单接收一下消息队列:
消息队列其实就是一个消息的链表。它提供了一个从一个进程向另一个进程发送一块数据的方法,每个数据块都被认为是有一个类型,接收者进程接受的数据块可以有不用的类型值。
消息队列也有不足之处,每个消息队列的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数也是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)
消息队列的生命周期随内核
二、消息队列的有关函数
(1)msgget函数:用来创建和访问一个消息队列
// 函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
// 参数:
(1)key:某个消息队列的名字
(2)msgflg:由九个权限标志构成,他们的用法和创建文件时使用的mode模式标
志是一样的
// 返回值:
成功返回该消息队列的标识码(一个非负整数);失败返回-1
(2)msgctl函数:消息队列的控制函数
// 函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
// 参数:
(1)msqid:由msgget函数返回的消息队列标识码
(2)cmd:是将要采取的动作(由三个可取值)
* IPC_STAT:把msqid_ds结构中的数据设置为消息队列的当前关联值
* IPC_SET:在进程有足够的权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
* IPC_RMID:删除消息队列
// 返回值:
成功返回0;失败返回-1
(3)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);
// 参数:
(1)msgid:由msgget函数返回的消息队列标识码
(2)msgp:是一个指针,指针指向准备发送的消息
(3)msgsz:是msgp指向的消息长度,这个长度不包含消息类型的那个长整型(long int)
(4)msgflg:控制着当前消息队列队满或到达系统上限时将要发生的事情
(5)msgflg=IPC_NOWAIT表示队满不等待,返回EAGAIN错误
// 返回值:
成功返回0;失败返回-1
// 说明:消息队列在两方面受到限制,一是必须小于系统规定的上限值;二为必须以一个长整型开始,接受者函数将利用这个长整型确定消息的类型
消息结构参考形式(该结构体必须由用户自己设计)
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
(4)msgrcv函数:从一个消息队列接受消息
// 函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
// 参数:
(1)msgid:由msgget函数返回的消息队列标识码
(2)msgp:是一个指针,指针指向准备发送的消息
(3)msgsz:是msgp指向的消息长度,这个长度不包含消息类型的那个长整型(long int)
(4)msgflg:控制着当前消息队列队满或到达系统上限时将要发生的事情
(5)msgtype:可以实现接受优先级的简单形式
// 返回值:
成功返回实际放到接受缓冲区里的字符个数;失败返回-1
*(5)ipcs & ipcrm命令
ipcs:显示IPC资源
* ipcs -m 查看系统共享内存信息
* ipcs -q 查看系统消息队列信息
* ipcs -s 查看系统信号量信息
ipcrm:手动删除IPC资源
* ipcrm -q msgid 移除用msgid标识的消息队列
显式消息队列有两种:一是命令;二是通过接口
三、代码模拟实现一下消息队列之间的通信
先写Makefile
comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include <stdio.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 msgid);
int sendMsg(int msgid, int who, char* msg);
int recvMsg(int msgid, int recvType, char out[]);
comm.c
#include "comm.h"
static int commMsgQueue(int flags)
{
key_t key = ftok("/tmp", 0x6666);
if (key < 0)
{
perror("ftok");
return -1;
}
int msgid = msgget(key, flags);
if (msgid < 0)
{
perror("msgget");
}
return msgid;
}
int createMsgQueue()
{
return commMsgQueue(IPC_CREAT | IPC_EXCL | 0666);
}
int getMsgQueue()
{
return commMsgQueue(IPC_CREAT);
}
int destoryMsgQueue(int msgid)
{
if (msgctl(msgid, IPC_RMID, NULL) < 0)
{
perror("msgctl");
return -1;
}
return 0;
}
int sendMsg(int msgid, int who, char* msg)
{
struct msgbuf buf;
buf.mtype = who;
strcpy(buf.mtext, msg);
if (msgsnd(msgid, (void*)&buf, sizeof(buf.mtext), 0) < 0)
{
perror("msgsnd");
return -1;
}
return 0;
}
int recvMsg(int msgid, int recvType, char out[])
{
struct msgbuf buf;
int size = sizeof(buf.mtext);
if (msgrcv(msgid, (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();
char buf[1024];
while (1)
{
buf[0] = 0;
recvMsg(msgid, CLIENT_TYPE, buf);
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;
sendMsg(msgid, SERVER_TYPE, buf);
printf("send done, wait recv...\n");
}
}
destorymsgQueue(msgid);
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 recv...\n");
}
recvMsg(msgid, SERVER_TYPE, buf);
printf("server# %s\n", buf);
}
return 0;
}