1,Linux 中的消息队列
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法,在Linux 系统中消息队列本质上是内核空间的链表【链表型队列】,每一个节点代表一个消息,每一个消息都有自己的类型【long type】。
消息队列与命名管道一样的不足,Linux用宏: MSGMAX
来限制一条消息的最大长度; MSGMNB
一个消息队列的最大长度(总的字节数是有上限的); MSGMNI
系统上消息队列的总数也有一个上限
2,LINUX 消息队列 API
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
//创建和访问一个消息队列
int msgget( key_t key, int msgFlg );
key: 某个消息队列的名字;
msgFlg:
IPC_CREAT :创建消息队列
IPC_EXCl :存在该消息队列,就报错
mode :访问权限(0644) (只需要设置读写权限,执行权限无效)
注:如果key = IPC_PRIVATE ,则自动产生一个随机未用的新键值
rertun:
ERROR -1
SUCCESS 消息队列的ID
//发送一个消息
int msgsnd( int msgID, const void *msgp, size_t msgsz, int msgflg )
msgsnd :消息队列的ID
msgp: 要发送的数据的地址
msgsz : 要发送的数据大小(不包括标识msg类型的长度)
msgflg :
IPC_NOWAIT 非阻塞读出、写入消息
MSG_EXCEPT 读取标识不是msgtype的第一个消息 (msgrcv)
MSG_NOERROR 消息尺寸比msgsz大时,截断消息而不报错
return
ERROR < 0
success 0
//接收一个消息
int msgrcv( int msgID, void *msgp, size_t msgsz, long msgtype, int msgflg)
同上:
msgtype :接收的消息标识符
msgsz :为一个消息的完整大小包括标识
注:
参数 msgtyp:指定获取哪种类型的消息
msgtyp = 0:获取消息队列中的第一条消息
msgtyp > 0:获取类型为 msgtyp 的第一条消息,
除非指定了 msgflg 为MSG_EXCEPT,这表示获取除了 msgtyp 类型以外的第一条消息。
msgtyp < 0:获取类型 ≤|msgtyp|≤|msgtyp| 的第一条消息。(-5 < msgtype < 5)
发送时的消息标识一般不能为 0
//删除 ipc
int msgctl( int msgID, int cmd, struct msgid_ds *buf)
cmd:
IPC_RMID 删除消息队列,忽略buf ==>success 0 ,ERROR < 0
IPC_STAT 获取该MSG的信息,存储到buf
IPC_SET 设置该MSG的信息
IPC_INFO 获取当前系统中MSG的限制信息
MSG_INFO 获取当前系统中MSG的资源消耗情况
MSG_STAT 。。。
3,消息队列的实例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <error.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MSG_key "/tmp/1.txt"
key_t msgKey = 0;
struct staff{
char Name[20];
int age;
};
struct msgbuf{
long mtype;
struct staff data;
};
void *recv_msgQueue(void *arg)
{
struct msgbuf buf;
int ret = 0;
key_t key = 0;
int msg_fd = 0;
int i = 0;
/*
if(0 > (key = ftok( MSG_key, 0)))
{
printf("pthread ftok error\n");
//return -1;
}
*/
if(0 > (msg_fd = msgget( msgKey, IPC_CREAT | 0666 )))
{
printf("pthread create msgget is error\n");
//return -1;
}
bzero( &buf, sizeof(buf));
while(1)
{
i++;
printf("msgrcv is waitting....[%d]\n", msg_fd);
ret = msgrcv( msg_fd, (void *)&buf, sizeof(buf), 1,0);
if(ret == -1)
{
printf("msg recv error\n");
}
printf("pthread is get msg,id [%d], Name [%s] , Age [%d]\n", buf.mtype, buf.data.Name, buf.data.age);
bzero( &buf, sizeof(buf));
if(i > 7)
{
msgctl(msg_fd,IPC_RMID,NULL);
exit(0);
}
sleep(2);
}
}
int main()
{
pthread_t tid = -1;
int ret = -1 , msg_fd = -1 ,i=0;
struct msgbuf Mymsg[5]={{ 1, "Jack", 27},{ 1, "Alice", 30},{ 1, "Lura", 35},\
{2, "Kang", 40},{2, "Wang", 45}};
//get key
msgKey = ftok( MSG_key, 0);
//create msgQueue
msg_fd = msgget(msgKey , IPC_CREAT | 0666);
if(msg_fd < 0)
{
printf("msgget create is error\n");
return -1;
}
//printf("Mymsg[0]:[%d][%s]\n", Mymsg[0].mtype, Mymsg[0].Name);
ret = pthread_create( &tid, NULL, recv_msgQueue , NULL );
if(ret < 0)
{
printf("pthread_create is error\n");
return -1;
}
ret = 0;
while(1) //不断发送消息
{
ret = msgsnd( msg_fd, (void *)&Mymsg[i], sizeof(Mymsg[i].data), 0);
if(i == 4)
{
ret = 0;
i=0;
continue;
}
if(ret < 0) printf("msg send error\n");
i++;
printf("msgsnd to msg [%d][%d]\n", i, msg_fd);
sleep(3);
}
}