進程間通信之消息隊列

一、消息隊列?
消息隊列是個什麼東東嘞?它其實就是有點像我們玩的qq啊微信啊什麼的,實現彼此之間的消息互發。目前有兩種類型的消息隊列:POSIX消息隊列和System V消息隊列。本篇博客學習的是System V消息隊列。下面來簡單接收一下消息隊列:

消息隊列其實就是一個消息的鏈表。它提供了一個從一個進程向另一個進程發送一塊數據的方法,每個數據塊都被認爲是有一個類型,接收者進程接受的數據塊可以有不用的類型值。

消息隊列也有不足之處,每個消息隊列的最大長度是有上限的(MSGMAX),每個消息隊列的總的字節數也是有上限的(MSGMNB),系統上消息隊列的總數也有一個上限(MSGMNI)

  消息隊列的生命週期隨內核

二、消息隊列的有關函數
(1)msgget函數:用來創建和訪問一個消息隊列

//  函數原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);

// 參數:1)key:某個消息隊列的名字
      (2)msgflg:由九個權限標誌構成,他們的用法和創建文件時使用的mode模式標                                                                
志是一樣的

//  返回值:
             成功返回該消息隊列的標識碼(一個非負整數);失敗返回-1

(2)msgctl函數:消息隊列的控制函數

//  函數原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

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

// 參數:1)msqid:由msgget函數返回的消息隊列標識碼
      (2)cmd:是將要採取的動作(由三個可取值)

    * IPC_STAT:把msqid_ds結構中的數據設置爲消息隊列的當前關聯值
    * IPC_SET:在進程有足夠的權限的前提下,把消息隊列的當前關聯值設置爲msqid_ds數據結構中給出的值
    * IPC_RMID:刪除消息隊列


//  返回值:
             成功返回0;失敗返回-1

(3)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);


// 參數:1)msgid:由msgget函數返回的消息隊列標識碼
      (2)msgp:是一個指針,指針指向準備發送的消息
            (3)msgsz:是msgp指向的消息長度,這個長度不包含消息類型的那個長整型(long  int)
            (4)msgflg:控制着當前消息隊列隊滿或到達系統上限時將要發生的事情
            (5)msgflg=IPC_NOWAIT表示隊滿不等待,返回EAGAIN錯誤

//  返回值:
             成功返回0;失敗返回-1

//  說明:消息隊列在兩方面受到限制,一是必須小於系統規定的上限值;二爲必須以一個長整型開始,接受者函數將利用這個長整型確定消息的類型

消息結構參考形式(該結構體必須由用戶自己設計)


struct msgbuf {
               long mtype;       /* message type, must be > 0 */
               char mtext[1];    /* message data */
           };

(4)msgrcv函數:從一個消息隊列接受消息

//  函數原型:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);

// 參數:1)msgid:由msgget函數返回的消息隊列標識碼
      (2)msgp:是一個指針,指針指向準備發送的消息
            (3)msgsz:是msgp指向的消息長度,這個長度不包含消息類型的那個長整型(long  int)
            (4)msgflg:控制着當前消息隊列隊滿或到達系統上限時將要發生的事情
            (5)msgtype:可以實現接受優先級的簡單形式

//  返回值:
             成功返回實際放到接受緩衝區裏的字符個數;失敗返回-1

*(5)ipcs & ipcrm命令
ipcs:顯示IPC資源

* ipcs -m  查看系統共享內存信息
* ipcs -q  查看系統消息隊列信息
* ipcs -s  查看系統信號量信息

ipcrm:手動刪除IPC資源

* ipcrm -q msgid  移除用msgid標識的消息隊列

顯式消息隊列有兩種:一是命令;二是通過接口

三、代碼模擬實現一下消息隊列之間的通信

先寫Makefile
這裏寫圖片描述

comm.h

#ifndef _COMM_H_
#define _COMM_H_
#include <stdio.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 msgid);
int sendMsg(int msgid, int who, char* msg);
int recvMsg(int msgid, int recvType, char out[]);

comm.c

#include "comm.h"
static int commMsgQueue(int flags)
{
      key_t key = ftok("/tmp", 0x6666);
      if (key < 0)
          {
              perror("ftok");
              return -1;
           }

       int msgid = msgget(key, flags);
       if (msgid < 0)
           {
               perror("msgget");
           }
       return msgid;
}
int createMsgQueue()
{
    return commMsgQueue(IPC_CREAT | IPC_EXCL | 0666);
}
int getMsgQueue()
{
      return commMsgQueue(IPC_CREAT);
}
int destoryMsgQueue(int msgid)
{
      if (msgctl(msgid, IPC_RMID, NULL) < 0)
          {
              perror("msgctl");
              return -1;
          }
      return 0;
}
int sendMsg(int msgid, int who, char* msg)
{
      struct msgbuf buf;
      buf.mtype = 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 recvType, char out[])
{
      struct msgbuf buf;
      int size = sizeof(buf.mtext);
      if (msgrcv(msgid, (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();

      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, wait recv...\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, wait recv...\n");
                     }
                 recvMsg(msgid, SERVER_TYPE, buf);
                 printf("server# %s\n", buf);
      }
      return 0;
}
發佈了55 篇原創文章 · 獲贊 9 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章