一、消息隊列?
消息隊列是個什麼東東嘞?它其實就是有點像我們玩的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;
}