一、什麼是消息隊列?
消息隊列提供了一種從一個進程向另一個進程發送一個數據塊的方法。 每個數據塊都被認爲是有一個類型,接收者進程接收的數據塊可以有不同的類型值。我們可以通過發送消息來避免命名管道的同步和阻塞問題。消息隊列與管道不同的是,消息隊列是基於消息的,而管道是基於字節流的,且消息隊列的讀取不一定是先入先出。消息隊列與命名管道有一樣的不足,就是每個消息的最大長度是有上限的(MSGMAX),每個消息隊列的總的字節數是有上限的( MSGMNB),系統上消息隊列的總數也有一個上限( MSGMNI)。
二、函數
1.創建新消息隊列或取得已存在消息隊列原型: int msgget(key_t key, int msgflg);參數:
key:可以認爲是一個端口號,也可以由函數ftok生成。
msgflg:
IPC_CREAT 如果IPC不存在,則創建一個IPC資源,否則打開操作。
IPC_EXCL:只有在共享內存不存在的時候,新的共享內存才建立,否則就產生錯誤。如果單獨使用IPC_CREAT, XXXget()函數要麼返回一個已經存在的共享內存的操作符,要麼返回一個新建的共享內存的標識符。如果將IPC_CREAT和IPC_EXCL標誌一起使用, XXXget()將返回一個新建的IPC標識符;如果該IPC資源已存在,或者返回-1。
IPC_EXEL標誌本來並沒有太大的意義,但是和IPC_CREAT標誌一起使用可以來保證所得的對象是新建的,而不是打開已有的對象。
2.向隊列讀/寫消息原型:
msgrcv從隊列中取出消息: ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, intmsgflg);
msgsnd將數據放到消息隊列中: int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
參數:
msqid:消息隊列的標識碼
msgp:指向消息緩衝區的指針,此位置用來暫時存儲發送和接收的消息,是一個用戶可定義的通用結構,形態如下:
struct msgstru{
long mtype; //大於0
char mtext[用戶指定大小];
};
msgsz:消息的大小。
msgtyp:從消息隊列內讀取的消息形態。如果值爲零,則表名消息隊列中的所有消息都會被讀取。
msgflg:用來指明核心程序在隊列沒有數據的情況下所應採取的行動。如果msgflg和常數IPC_NOWAIT合用,則在msgsnd()執行時若是消息隊列已滿,則msgsnd()將不會阻塞,會立即返回-1,如果執行的是msgrcv(),則在消息隊列呈空時,不做等待馬上返回-1,並設定錯誤碼爲ENOMSG。當msgflg爲0時, msgsnd()及msgrcv()在隊列呈滿或呈空的情形時,採取阻塞等待的處理模式。
3.設置消息隊列屬性原型: int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );參數: msgctl 系統調用對 msgqid 標識的消息隊列執行cmd 操作,系統定義了 3 種 cmd 操作: IPC_STAT , IPC_SET , IPC_RMID
IPC_STAT : 該命令行來獲取消息隊列對應的 msqid_ds 數據結構,並將其保存到 buf 指定的地址空間。
IPC_SET : 該命令用來設置消息隊列的屬性,要設置的屬性存儲在buf中。
IPC_RMID : 從內核中刪除 msqid 標識的消息隊列。
廢話不多說貼上代碼纔有說服性:
comm.h:
#pragma once
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include<errno.h>
#define _PROJ_NAME_ "/tmp"
#define _PROJ_ID_ 0X666
#define _SIZE_ 1024
#define _SEVER_TYPE_ 1
#define _CLIENT_TYPE_ 2
struct msgbuf{
long mtype;
char mtext[_SIZE_];
};
int create_msg_queue();//創建消息隊列
int get_msg_queue(); //得到消息隊列
int destroy_msg_queue(int msg_id);//銷燬消息隊列
int recv_msg(int msg_id,int t, char*out);//接收消息
int send_msg(int msg_id,int t,const char*msg);//發送消息
comm.c:
#include"comm.h"
static int com_msg_queue(int flags)
{
key_t _key=ftok(_PROJ_NAME_,_PROJ_ID_);
if(_key<0)
{
perror("ftok");
return -1;
}
int msg_id=msgget(_key,flags);
if(msg_id<0)
{
perror("msgget");
}
return msg_id;
}
int create_msg_queue()
{
int flags=IPC_CREAT|IPC_EXCL|0644;
return com_msg_queue(flags);
}
int get_msg_queue()
{
int flags=IPC_CREAT;
return com_msg_queue(flags);
}
int destroy_msg_queue(int msg_id)
{
if(msgctl(msg_id,IPC_RMID,NULL)<0)
{
perror("msgctl");
return -1;
}
return 0;
}
int send_msg(int msg_id,int t,const char*msg)
{
struct msgbuf _msg;
_msg.mtype=t;
strncpy(_msg.mtext,msg,strlen(msg)+1);
if(msgsnd(msg_id,&_msg,sizeof(_msg.mtext),0)<0)
{
perror("msgsnd");
return -1;
}
return 0;
}
int recv_msg(int msg_id,int t,char*out)
{
struct msgbuf _msg;
_msg.mtype=t;
memset(_msg.mtext,'\0',sizeof(_msg.mtext));
if(msgrcv(msg_id,&_msg,sizeof(_msg.mtext),t,0)<0)
{
perror("msgrcv");
return -1;
}
else
{
strcpy(out,_msg.mtext);
}
return 0;
}
client.c:
#include"comm.h"
int main()
{
int msg_id=get_msg_queue();
char buf[_SIZE_];
while(1)
{
printf("please enter:");
fflush(stdout);
read(0,buf,sizeof(buf)-1);
send_msg(msg_id,_CLIENT_TYPE_,buf);
memset(buf,'\0',sizeof(buf));
recv_msg(msg_id,_SEVER_TYPE_,buf);
printf("sever->client:%s\n",buf);
}
return 0;
}
server.c:
#include"comm.h"
int main()
{
int msg_id=create_msg_queue();
char buf[_SIZE_];
while(1)
{
memset(buf,'\0',sizeof(buf));
sleep(20);
recv_msg(msg_id,_CLIENT_TYPE_,buf);
printf("client->sever:%s\n",buf);
printf("please enter:");
fflush(stdout);
read(0,buf,sizeof(buf)-1);
send_msg(msg_id,_SEVER_TYPE_,buf);
}
destroy_msg_queue(msg_id);
return 0;
}