進程間通信-消息對列

原理說明:

消息隊列是內核地址空間中的內部鏈表,通過linux內核在各個進程之間傳遞內容,消息順序地發送到消息隊列中,並且以幾種不同的方式

從隊列中獲取,每個消息隊列可以用IPC標識符唯一的進行標識,內核中的消息隊列是通過IPC的標識符來區別的,不同的消息隊列之間是

相互獨立的,每個消息隊列中的消息又構成一個獨立的鏈表.

 

消息隊列中的數據結構

1、消息緩衝結構

向消息隊列發送消息時,必須組成合理的數據結構。Linux系統定義了一個模版數據結構msgbuf:

#include<linux/msg.h>

struct msgbuf{

long type;

char mtext[1];

}

其中type表示消息的類型,以正數表示。mtext是該消息的數據,並不一定就是char 類型,任意類型都可以的。

2、msqid_ds內核數據結構。

struct msqid_ds{

   struct ipc_perm msg_perm;

   time_t msg_stime;

   time_t msg_rtime;

   time_t msg_ctime;

   unsigned long _msg_cbuyes;

    ..........

   };

 

Linux內核中,每個消息隊列都維護一個結構體,此結構體保存着消息隊列當前狀態信息,該結構體在頭文件linux/msg.h中定義。

3、ipc_perm內核數據結構

struct ipc_perm{

  key_t key;

  uid_t uid;

  gid_t gid;

  .......

};

結構體ipc_perm保存着消息隊列的一些重要的信息,比如說消息隊列關聯的鍵值,消息隊列的用戶id組id等。它定義在頭文件linux/ipc.h中

 

Linux的消息隊列(queue)實質上是一個鏈表, 它有消息隊列標識符(queue ID). msgget創建一個新隊列或打開一個存在的隊列; msgsnd向隊列末端

添加一條新消息; msgrcv從隊列中取消息, 取消息是不一定遵循先進先出的, 也可以按消息的類型字段取消息. 

 

 

 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

  int msgget(key_t key, int msgflg);

 

參數key是一個鍵值,由ftok獲得;msgflg參數是一些標誌位。該調用返回與健值key相對應的消息隊列描述字,如果沒有消息隊列與健值key相對應,

並且msgflg中包含了IPC_CREAT標誌位或者key參數爲IPC_PRIVATE,那麼該調用將創建一個新的消息隊列。

 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);

該系統調用從msgid代表的消息隊列中讀取一個消息,並把消息存儲在msgp指向的msgbuf結構中。

 msqid爲消息隊列描述字;消息返回後存儲在msgp指向的地址,msgsz指定msgbuf的mtext成員的長度(即消息內容的長度),msgtyp爲請求讀

取的消息類型,成功返回讀出消息的實際字節數,否則返回-1。

 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);

向msgid代表的消息隊列發送一個消息,即將發送的消息存儲在msgp指向的msgbuf結構中,消息的大小由msgze指定。

 對發送消息來說,有意義的msgflg標誌爲IPC_NOWAIT,指明在消息隊列沒有足夠空間容納要發送的消息時,msgsnd是否等待。成功返回0,否則

返回-1。

 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

該系統調用對由msqid標識的消息隊列執行cmd操作,共有三種cmd操作:IPC_STAT、IPC_SET 、IPC_RMID。

 

IPC_STAT:該命令用來獲取消息隊列信息,返回的信息存貯在buf指向的msqid結構中;

IPC_SET:該命令用來設置消息隊列的屬性,要設置的屬性存儲在buf指向的msqid結構中;可設置屬性包括:msg_perm.uid、msg_perm.gid、

                msg_perm.mode以及msg_qbytes,同時,也影響msg_ctime成員。

IPC_RMID:刪除msqid標識的消息隊列;

 

 

 

read.c

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
#include <stdio.h>

typedef struct msg_st
{
    long int msg_type;
    char text[BUFSIZ];
} MSG_ST ;

int main()
{
    int running = 1;
    int msgid = -1;
    MSG_ST data;
    long int msgtype = 2;
    
    msgid =  msgget((key_t)1234,0666 | IPC_CREAT);
    
    if(msgid == -1)
    {
        puts("msgget fail \n");
        exit(EXIT_FAILURE);
    }
    
    while(running)
    {
        if(msgrcv(msgid,(void *)&data,BUFSIZ,msgtype,0) == -1)
        {
            puts("msgrcv fail \n");
            exit(EXIT_FAILURE);
        }
        printf("rcv data type %d\n",data.msg_type);
        printf("rcv data text %s\n",data.text);
        
        if(strncmp(data.text,"end",3)==0)
            running = 0;
    }
    
    if(msgctl(msgid,IPC_RMID,0)==-1)
    {
        printf(stderr,"msgctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_FAILURE);

}

 

write.c

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/msg.h>
#include <errno.h>
#define MAX_TEXT 512
typedef struct msg_st
{
    long int msg_type;
    char text[MAX_TEXT];
}MSG_ST;

int main()
{
    int running = 1 ;
    struct msg_st data;
    char buffer[BUFSIZ];
    int msgid = -1;
    printf("bufsize size is %d\n",BUFSIZ);
    printf("MAX_TEXT is %d\n",MAX_TEXT);
    
    msgid = msgget((key_t)1234,0666 | IPC_CREAT);
    if(msgid == -1)
    {
        puts("msgget fail !\n");
        exit(EXIT_FAILURE);    
    }
    
    while(running)
    {
        puts("input data");
        fgets(buffer,BUFSIZ,stdin);
        data.msg_type = 2;
        strcpy(data.text,buffer);
        
        if(msgsnd(msgid,(void *)&data,MAX_TEXT,0) == -1)
        {
            puts("msgsnd fail !\n");
            exit(EXIT_FAILURE);            
        }
        
        if(strncmp(buffer,"end",3)==0)
            running = 0;
        sleep(1);
                
    }
    puts("exit success\n");
    exit(EXIT_FAILURE);
    


}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章