1. 程式人生 > >Linux訊息佇列實現程序間通訊

Linux訊息佇列實現程序間通訊

什麼是訊息佇列: 訊息佇列提供了從一個程序向另一個程序傳送一個有型別資料塊的方法。用這種方法可以避免命名管道的同步和阻塞問題。訊息佇列是基於訊息的,而管道是基於位元組流的,並且訊息佇列的讀取不一定是先入先出。 訊息佇列的操作: 訊息佇列的建立或者獲取: int msgget(key_t key, int msgflg); 引數描述: key:是一個埠號,可以由ftok()生成 msgflg:  IPC_CREAT:如果IPC不存在,則建立,存在就開啟                 IPC_EXECL:單獨使用無太大意義,與IPC_CREAT一塊使用代表,IPC不存在建立,存在出錯,返回 key_t ftok(const char *pathname, int proj_id); 生成唯一一個key供使用者使用,返回一個訊息佇列識別符號。 返回值: 成功返回訊息佇列的id,失敗返回-1。 讀取訊息:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); 引數描述: msgid:訊息佇列的識別符號 msgp:指向一個緩衝區的指標,用來暫時存放儲存傳送和接受的訊息,是一個使用者可以定義的通用結構。 struct msgstru{     long mtype; //大於0     char mtext;//使用者指定大小 }; msgz:訊息的大小 msgtyp:從訊息佇列中讀取的訊息形態 msgflg:用來指明核心程式在佇列沒有資料的情況下所應採取的行動。如果msgflg和常 數IPC_NOWAIT合用,則在msgsnd()執行時若是訊息佇列已滿,則msgsnd()將不會阻塞,而 會立即返回-1,如果執⾏行的是msgrcv(),則在訊息佇列呈空時,不做等待馬上返回-1,並設定 錯誤碼為ENOMSG。當msgflg為0時,msgsnd()及msgrcv()在佇列呈滿或呈空的情形時,採取 阻塞等待的處理模式。 返回值: 成功返回實際讀取到的位元組數,失敗返回-1。 傳送訊息:
int msgsnd(int msqid, const void *msgp, size_t msgz, int msgflg); 引數與讀取訊息函式的引數相同。 返回值; 成功返回0,失敗返回-1。 訊息佇列的檢視: 可以使用 ipcs -q 來檢視系統中的訊息佇列; 可以使用ipcrm -q +訊息佇列id  來刪除對應id的訊息佇列 訊息佇列的例項: 實現一個server和一個client程式,他們之間利用訊息佇列進行通訊。 comm.h
#ifndef  _COMM_H_
#define  _COMM_H_
#ifndef  _COMM_H_
#define  _COMM_H_

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

#define PATHNAME "."
#define PROJ_ID 0x666

#define SERVER_TYPE 1
#define CLIENT_TYPE 2

//自定義一個緩衝區用來暫時儲存傳送或者接收的資料
struct msgbuf
{
    long mytype;
    char mtext[1024];
};
int createMsgQueue();
int getMsgQueue();
int destroyMsgQueue(int msgid);
int sendMsg(int msgid, int type, char *msg);
int recvMsg(int msgid, int recvType, char out[]);
#endif
comm.c
#include "comm.h"

//建立或者開啟訊息佇列
static int commMsgQueue(int flag)
{
    key_t key = ftok(PATHNAME, PROJ_ID);
    if(key < 0)
    {
    perror("ftok");
    return -1;
    }
    //根據flag的不同選擇開啟還是建立
    int msgid = msgget(key, flag);
    if(msgid < 0)
    {
    perror("msgget");
    return -2;
    }
    return msgid;
}
int createMsgQueue()
{
    return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}
int getMsgQueue()
{
    return commMsgQueue(IPC_CREAT);
}
int destroyMsgQueue(int msgid)
{
    //刪除訊息佇列
    if(msgctl(msgid, IPC_RMID, NULL)<0)
    {
    perror("msgctl");
    return -1;
    }
    return 0;
}
//傳送訊息(引數:傳送者,傳送內容的型別,傳送的內容)
int sendMsg(int msgid, int who, char *msg)
{
    //buf 自定義的緩衝區,用來暫存資料
    struct msgbuf buf;
    buf.mytype = 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 who, char out[])
{
    struct msgbuf buf;
    buf.mytype = who;
    //接收資料,將接收的資料寫入到緩衝區中
    if(msgrcv(msgid, (void *)&buf, sizeof(buf.mtext), recvType, 0)< 0)
    {
    perror("msgrcv");
    return -1;
    }
    //將資料從緩衝區存放到指定位置
    strcpy(out, buf.mtext);
    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...\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...\n");
    }
    //接受伺服器的迴應
    recvMsg(msgid, SERVER_TYPE, buf);
    printf("Server : %s\n", buf);

    }
   return 0;
}
執行結果: