1. 程式人生 > 其它 >程序間通訊-訊息佇列

程序間通訊-訊息佇列

技術標籤:程序間通訊

場景:同一臺linux裝置下,多個程序之間資料要互相通訊,就可以使用訊息佇列進行資料傳輸。

訊息佇列(Message Queue):是訊息的連結串列,存放在核心中並由訊息佇列識別符號標識

  • 優點:可以實現任意程序間的通訊,並通過系統呼叫函式來實現訊息傳送和接收之間的同步,無需考慮同步問題,方便
  • 缺點:資訊的複製需要額外消耗 CPU 的時間,不適宜於資訊量大或操作頻繁的場合

訊息佇列提供了一個從一個程序向另一個程序傳送資料塊的方法,每個資料塊都可以被認為是有一個型別,接收者接受的資料塊可以有不同的型別。

訊息佇列函式:

1、msgget
功能:建立和訪問一個訊息佇列
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflag);
引數:
key:訊息佇列名稱,用ftok()產生
msgflag:IPC_CREAT或者IPC_EXCL,如果訊息佇列不存在則建立之,如果存在則開啟返回;單獨使用IPC_EXCL是沒有意義的;兩個同時使用,如果訊息佇列不存在則建立之,如果存在則出錯返回。
返回值:成功返回非負整數,即訊息佇列的標識碼,失敗返回-1

2、ftok
功能:建立訊息佇列名稱
原型:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
返回值:成功返回一個key值,用於建立訊息佇列,失敗返回-1
3、msgctl
功能:訊息佇列的控制函式
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
引數:
mgqid:由msgget函式返回的訊息佇列標識
cmd:命令,這邊有三個命令
IPC_STAT把msqid_ds結構中的資料設定為訊息佇列的當前關聯值
IPC_SET在程序有足夠許可權的前提下,把訊息佇列的當前值設定為msqid_ds資料結構中給出的值
IPC_RMID刪除訊息佇列
返回值:成功返回0,失敗返回-1
4、msgsnd
功能:把一條訊息新增到訊息佇列中
原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
引數:
msgid:msgget函式返回的訊息佇列標識碼
msgp:指標指向準備傳送的訊息
msgsz:msgp指向的訊息的長度
msgflg:預設為0
返回值:成功返回0,失敗返回-1
傳送的訊息結構:
struct msgbuf
{
     long mtye;
     char mtext[1];
};
5、msgrcv
功能:從一個訊息佇列接收訊息
原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
引數:
msgid:msgget函式返回的訊息佇列標識碼
msgp:指標指向準備傳送的訊息
msgsz:msgp指向的訊息的長度
msgtyp:訊息型別
type==0,返回佇列中第一個訊息
type > 0, 返回佇列中訊息型別為type的第一個訊息
type < 0, 返回佇列中訊息型別值小於或等於type絕對值的訊息,如果這種訊息有若干個,則取型別值最小的訊息
msgflg:預設為0

上原始碼:

//comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
struct msgbuf
{
    long mtype;
    char mtext[1024];
};
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
int createMsgQueue();
int getMsgQueue();
int destoryMsgQueue(int msg_id);
int sendMsgQueue(int msg_id, int who, char *msg);
int recvMsgQueue(int msg_id, int recvType, char out[]);
#endif
//comm.c
#include "comm.h"
static int commMsgQueue(int cmd)
{
    key_t key = ftok("/tmp", 0x6666);
    if(key < 0)
    {
        perror("ftok");
        return -1;
    }
    int msg_id = msgget(key, cmd);
    if(msg_id < 0)
    {
        perror("msgget");
    }
    return msg_id;
}
int createMsgQueue()
{
    return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
}
int getMsgQueue()
{
    return commMsgQueue(IPC_CREAT);
}
int destoryMsgQueue(int msg_id)
{
    if(msgctl(msg_id, IPC_RMID, NULL) < 0)
    {
        perror("msgctl");
        return -1;
    }
    return 0;
}
int sendMsgQueue(int msg_id, int type, char *msg)
{
    struct msgbuf buf;
    buf.mtype = type;
    strcpy(buf.mtext, msg);
    if(msgsnd(msg_id, (void*)&buf, sizeof(buf.mtext), 0) < 0)
    {
        perror("msgsnd");
        return -1;
    }
    return 0;
}
int recvMsgQueue(int msg_id, int recvType, char out[])
{
    struct msgbuf buf;
    int size = sizeof(buf.mtext);
    if(msgrcv(msg_id, (void *)&buf, size, recvType, 0) < 0)
    {
        perror("msgrcv");
        return -1;
    }
    strncpy(out, buf.mtext, size);
    out[size] = 0;
    return 0;
}
//server.c
#include "comm.h"
int main()
{
    int msgid = createMsgQueue();
    printf("msgid = %d\n", msgid);
    char buf[1024] = {0};
    while(1)
    {
        recvMsgQueue(msgid, CLIENT_TYPE, buf);
        if(strcasecmp("quit", buf) == 0)
            break;
        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;
            sendMsgQueue(msgid, SERVER_TYPE, buf);
            printf("send done, wait recv...\n");
        }
        */
    }
    destoryMsgQueue(msgid);
    return 0;
}
//client.c
#include "comm.h"
int main()
{
    int msgid = getMsgQueue();
    printf("msgid:%d\n", msgid);
    char buf[1024] = {0};
    while(1)
    {
        printf("Please Enter:");
        fflush(stdout);
        ssize_t s = read(0, buf, sizeof(buf));
        if(s > 0)
        {
            buf[s - 1] = 0;
            sendMsgQueue(msgid, CLIENT_TYPE, buf);
            if(strcasecmp("quit", buf) == 0)
                break;
            //printf("send done, wait recv...\n");
        }
        //recvMsgQueue(msgid, SERVER_TYPE, buf);
        //printf("server#%s\n", buf);
    }
    return 0;
}

編譯執行client、server。

client傳送訊息:

[[email protected] tmp]# ./client

msgid:360448

Please Enter:AAAA

Please Enter:BBBBB

Please Enter:HEIIL

Please Enter:quit

[[email protected] tmp]#

server接收訊息:

[[email protected] tmp]# ./server

msgid = 360448

client:AAAA

client:BBBBB

client:HEIIL

[[email protected] tmp]#

ipcs -q :檢視IPC資源

ipcrm -q:刪除IPC資源

參考:

https://blog.csdn.net/wei_cheng18/article/details/79661495

https://www.cnblogs.com/nufangrensheng/p/3561820.html

https://blog.csdn.net/guoping16/article/details/6584024