1. 程式人生 > >System V程序間通訊---訊息佇列

System V程序間通訊---訊息佇列

一、訊息佇列模型
訊息佇列是訊息的鏈式佇列,下圖即為訊息佇列模型…
這裡寫圖片描述

1、訊息佇列的基本屬性

struct msqid_ds
{
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg msg_first; / first message on queue,unused */
struct msg msg_last; / last message in queue,unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};

2、建立訊息佇列

在我們使用訊息佇列之前,需要使用msgget函式建立該訊息佇列,其函式申明如下:

extern int msgget (key_t key , int msgflg) ;

key:函式ftok的返回值或IPC_PRIVATE。
msgflag: IPC_CREAT:建立新的訊息佇列。 IPC_EXCL:與IPC_CREAT一同使用,表示如果要建立的訊息佇列已經存在,則返回錯誤。 IPC_NOWAIT:讀寫訊息佇列要求無法滿足時,不阻塞。返回值: 呼叫成功返回佇列識別符號,否則返回-1.

3、傳送訊息到訊息佇列與從訊息佇列進行訊息的接收

傳送函式:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

接收函式:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

msqid:訊息佇列的識別碼。

msgp:指向訊息緩衝區的指標,此位置用來暫時儲存傳送和接收的訊息,是一個使用者可定義的通用結構,形態如下
struct msgbuf {
long mtype; /* 訊息型別,必須 > 0 */
char mtext[1]; /* 訊息文字 */
};

msgsz:訊息的大小。

msgtyp:訊息型別
msgtyp等於0 則返回佇列的最早的一個訊息。
msgtyp大於0,則返回其型別為mtype的第一個訊息。
msgtyp小於0,則返回其型別小於或等於mtype引數的絕對值的最小的一個訊息。

msgflg:這個引數依然是是控制函式行為的標誌,取值可以是:0,表示忽略;IPC_NOWAIT,如果訊息佇列為空,則返回一個ENOMSG,並將控制權交回呼叫函式的程序。如果不指定這個引數,那麼程序將被阻塞直到函式可以從佇列中得到符合條件的訊息為止。如果一個client 正在等待訊息的時候佇列被刪除,EIDRM 就會被返回。如果程序在阻塞等待過程中收到了系統的中斷訊號,EINTR 就會被返回。MSG_NOERROR,如果函式取得的訊息長度大於msgsz,將只返回msgsz 長度的資訊,剩下的部分被丟棄了。如果不指定這個引數,E2BIG 將被返回,而訊息則留在佇列中不被取出。當訊息從佇列內取出後,相應的訊息就從佇列中刪除了。

二、應用例項
傳送端程序:

/*
 *利用訊息佇列進行通訊的訊息傳送端
 */

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

/*
 *定義訊息結構體
 */
struct msgbuf
{
    long type ; //訊息型別
    char ptr[128] ; //訊息緩衝區
} ;


int main(int argc , char* argv[])
{
    key_t key ;
    key = ftok(argv[1] , 100) ; //建立約定通訊的鍵值key 

    int msgid ;
    msgid = msgget(key , IPC_CREAT | 0600) ; //進行訊息佇列的建立

    pid_t pid ;
    pid = fork() ; //建立用於資訊傳送的子程序

    if(pid == 0) //進行訊息傳送
    {
        while(1) //迴圈傳送
        {
            printf("please input msg to send : ") ;
            char buf[128] ;
            fgets(buf , 128 , stdin) ;
            struct msgbuf *ptr = malloc(sizeof(struct msgbuf)) ;

            //進行訊息的設定
            ptr->type = 1 ;
            memset(ptr->ptr , '\0' , 128) ;
            memcpy(ptr->ptr , buf , strlen(buf)) ;

            msgsnd(msgid , ptr , sizeof(struct msgbuf) , 0) ; //進行訊息的傳送


            free(ptr) ;
        }
    }else
    {
        //進行接收到的訊息的定義
        struct msgbuf{
            long type ;
            char ptr[1024] ; 
        } ;

        while(1) //進行訊息的迴圈接收
        {
            struct msgbuf mybuf ;
            memset(&mybuf , '\0' , sizeof(mybuf)) ; //進行清空

            msgrcv(msgid , &mybuf , 1024 , 2 , 0) ; //進行訊息的接收

            printf("recv msg : %s \n" , mybuf.ptr) ;            
        }   
    }

    return 0 ;
}

接收端程序:

/*
 *利用訊息佇列進行通訊的訊息接收端
 */

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

/*
 *定義訊息結構體
 */
struct msgbuf
{
    long type ; //訊息型別
    char ptr[128] ; //訊息緩衝區
} ;

int main(int argc , char* argv[])
{
    key_t key ;
    key = ftok(argv[1] , 100) ; //建立約定通訊的鍵值key 

    int msgid ;
    msgid = msgget(key , IPC_CREAT | 0600) ; //進行訊息佇列的建立

    pid_t pid ;
    pid = fork() ; //建立用於資訊傳送的子程序

    if(pid == 0) //進行訊息傳送
    {
        while(1) //迴圈傳送
        {
            printf("please input msg to send : ") ;
            char buf[128] ;
            fgets(buf , 128 , stdin) ;
            struct msgbuf *ptr = (struct msgbuf*)malloc(sizeof(struct msgbuf)) ;

            //進行訊息的設定
            ptr->type = 2 ;
            memset(ptr->ptr , '\0' , 128) ;
            memcpy(ptr->ptr , buf , strlen(buf)) ;

            msgsnd(msgid , ptr , sizeof(struct msgbuf) , 0) ; //進行訊息的傳送
            free(ptr) ;
        }
    }else
    {
        //進行接收到的訊息的定義
        struct msgbuf{
            long type ;
            char ptr[1024] ; 
        } ;

        while(1) //進行訊息的迴圈接收
        {
            struct msgbuf mybuf ;
            memset(&mybuf , '\0' , sizeof(mybuf)) ; //進行清空

            msgrcv(msgid , &mybuf , 1024 , 1 , 0) ; //進行訊息的接收

            printf("recv msg : %s \n" , mybuf.ptr) ;            
        }   
    }

    return 0 ;
}

可以檢視結果如下:
傳送端:
這裡寫圖片描述

接收端:
這裡寫圖片描述