天天看點

程序間通信----消息隊列Linux程序間通信——使用消息隊列消息隊列,就是一個消息的連結清單,是一系列儲存在核心中消息的清單。使用者程序可以向消息隊列添加消息,也可以向消息隊列讀取消息。

Linux程序間通信——使用消息隊列

消息隊列,就是一個消息的連結清單,是一系列儲存在核心中消息的清單。使用者程序可以向消息隊列添加消息,也可以向消息隊列讀取消息。

----->雙向通信

----->用于随意程序

------>面向資料塊(連結清單)

------>自帶同步互斥

------->生命周期随核心

消息隊列與管道通信相比,其優勢是對每個消息指定特定的消息類型,接收的時候不需要按照隊列次序,而是可以根據自定義條件接收特定類型的消息。

可以把消息看做一個記錄,具有特定的格式以及特定的優先級。對消息隊列有寫權限的程序可以向消息隊列中按照一定的規則添加新消息,對消息隊列有讀權限的程序可以從消息隊列中讀取消息。

程序間通過消息隊列通信,主要是:建立或打開消息隊列,添加消息,讀取消息和控制消息隊列。

消息隊列提供了一個從一個程序向另外一個程序發送一塊資料的方法

每個資料塊都被認為是有一個類型,接收者程序接收的資料塊可以有不同的類型值

消息隊列也有管道一樣的不足,就是每個消息的最大長度是有上限的(MSGMAX),每個消息隊列的總的位元組數是有上限的(MSGMNB),系統上消息隊列的總數也有一個上限(MSGMNI)------Linux用宏MSGMAX和MSGMNB來限制一條消息的最大長度和一個隊列的最大長度。

Linux提供了一系列消息隊列的函數接口來讓我們友善地使用它來實作程序間的通信

1、msgget函數 該函數用來建立和通路一個消息隊列。它的原型為: int msgget(key_t key, int msgflg); 

      key  -->某個消息隊列的名字

      msgflg  -->由9個權限辨別符構成,

傳回值:成功時傳回一個非負整數,即該消息隊列的辨別符,失敗傳回-1.

2、msgsnd函數 該函數用來把消息添加到消息隊列中。它的原型為: int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);   msgid是由msgget函數傳回的消息隊列辨別符。 msg_ptr是一個指向準備發送消息的指針,但是消息的資料結構卻有一定的要求,指針msg_ptr所指向的消息結構一定要是以一個長整型成員變量開始的結構體(由調用者定義的結構體,相當于連結清單的一個節點),接收函數将用這個成員來确定消息的類型。是以消息結構要定義成這樣: struct msgbuf{

     long mtype;//消息的類型

     char mtext[1];消息資料

};

msg_sz是msg_ptr指向的消息的長度,注意是消息的長度,而不是整個結構體的長度,也就是說msg_sz是不包括長整型消息類型成員變量的長度。(結構裡mtext數組的大小)

msgflg用于控制目前消息隊列滿或隊列消息到達系統範圍的限制時将要發生的事情。如果調用成功,消息資料的一分副本将被放到消息隊列中,并傳回0,失敗時傳回-1.

3、msgrcv函數 該函數用來從一個消息隊列擷取消息,它的原型為 int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);   msgid, msg_ptr, msg_st的作用也函數msgsnd函數的一樣。 msgtype可以實作一種簡單的接收優先級。如果msgtype為0,就擷取隊列中的第一個消息。如果它的值大于零,将擷取具有相同消息類型的第一個資訊。如果它小于零,就擷取類型等于或小于msgtype的絕對值的第一個消息。 msgflg用于控制當隊列中沒有相應類型的消息可以接收時将發生的事情。調用成功時,該函數傳回放到接收緩存區中的位元組數,消息被複制到由msg_ptr指向的使用者配置設定的緩存區中,然後删除消息隊列中的對應消息。失敗時傳回-1. 4、msgctl函數 該函數用來控制消息隊列,它的原型為: int msgctl(int msgid, int command, struct msgid_ds *buf);   command是将要采取的動作,它可以取3個值,     IPC_STAT:把msgid_ds結構中的資料設定為消息隊列的目前關聯值,即用消息隊列的目前關聯值覆寫msgid_ds的值。     IPC_SET:如果程序有足夠的權限,就把消息列隊的目前關聯值設定為msgid_ds結構中給出的值

    IPC_RMID:删除消息隊列 buf是指向msgid_ds結構的指針,它指向消息隊列模式和通路權限的結構。msgid_ds結構至少包括以下成員: struct msgid_ds

{       uid_t shm_perm.uid; 

       uid_t shm_perm.gid; 

       mode_t shm_perm.mode; 

};   成功時傳回0,失敗時傳回-1.

代碼執行個體:

系統建立IPC通訊(如消息隊列、共享記憶體時)必須指定一個ID值。通常情況下,該id值通過ftok函數得到。

ftok原型如下:

key_t ftok( char * fname, int id )

fname就時你指定的檔案名(該檔案必須是存在而且可以通路的),id是子序号,雖然為int,但是隻有8個比特被使用(0-255)。

當成功執行的時候,一個key_t值将會被傳回,否則 -1 被傳回。

server.c

1 #include "messages.h"
  2 int main(){
  3    int msgid = createMsgQueue();
  4    char buf[1024];
  5    while(1){
  6    buf[0]=0;
  7    recvMsg(msgid,CLIENT_TYPE,buf);
  8    printf("client# %s\n", buf);
  9    fflush(stdout);
 10    ssize_t s = read(0,buf,sizeof(buf));
 11    if(s>0){
 12       buf[s-1]=0;
 13      sendMsg(msgid,SERVER_TYPE,buf);
 14     printf("send done,wait recv...\n");
 15    }
 16    }                                                                                                                 
 17   destroyMsgQueue(msgid);
 18   return 0;
 19 }
           

client.c

1 #include "messages.h"
  2 #include<stdio.h>
  3 int main(){
  4    int msgid = getMsgQueue();
  5    char buf[1024];
  6    while(1){
  7      buf[0]=0;
  8      printf("please enter# ");
  9      fflush(stdout);
 10      size_t s = read(0,buf,sizeof(buf));
 11      if(s>0){
 12      buf[s-1]=0;
 13      sendMsg(msgid,CLIENT_TYPE,buf);                                                                                 
 14      printf("send done,wait recv...\n");
 15      }
 16    }
 17    return 0;
 18 }
           

messages.c

1 #include "messages.h"
  2 static int commMsgQueue(int flags){
  3    key_t key = ftok(PATHNAME,PROJ_ID);
  4    if(key<0){
  5     perror("ftok");
  6     return -1;
  7     }
  8     int msgid = msgget(key,flags);
  9     if(msgid<0){
 10       perror("msgget");
 11     }
 12    return msgid;
 13 }
 14 int createMsgQueue()
 15 {
 16    return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
 17 
 18 }
 19 int getMsgQueue(){
 20    return commMsgQueue(IPC_CREAT);
 21 }
 22 int destroyMsgQueue(int msgid){
 23 //控制消息隊列
 24    if(msgctl(msgid,IPC_RMID,NULL)<0){
 25       perror("msgctl");
 26       return -1;
 27 }
 28 return 0;
 29 }
 30 int sendMsg(int msgid,int who,char *msg){
 31      struct msgbuf buf;
 32      buf.mtype = who;
 33      strcpy(buf.mtext,msg);
 34      //把消息添加到隊列中
 35      if(msgsnd(msgid,(void *)&buf,sizeof(buf.mtext),0)<0){
 36         perror("msgnd");
 37         return -1;
 38    }
 39    return 0;
 40 }
 41 int recvMsg(int msgid,int recvType,char out[]){
 42     struct msgbuf buf;
 43     if(msgrcv(msgid,(void*)&buf,sizeof(buf.mtext),recvType,0)<0){
 44      perror("msgrcv");
 45      return -1;
 46     
 47 }
           

messages.h

#include<stdio.h>
#include<sys/types.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 destoryMsgQueue(int msgid);
int sendMsg(int msgid,int who,char *msg);
int recvMsg(int msgid,int recvType,char out[]); 
           

繼續閱讀