進程間通信(二):消息隊列

消息隊列是操作系統爲兩個無關進程準備的通信方式,每個消息隊列都有一個他自己的ID我們用來標識消息隊列

消息隊列的不足就是我們發送消息的最大長度有限制,並且操作系統提供的消息隊列的個數也是有限的

此ID用如下函數創建

此函數中的path爲一個路徑,講道理這個路徑其實可以隨便定義,一般定義成當前目錄即可,然後這個proj_id就是一個數字而已可以隨便設,啊就是這樣,但是我們要知道同一個路徑同一個項目ID數完全有可能產生同一個消息隊列ID的,並且我們要注意的是消息隊列和管道不一樣,管道的生命隨進程,但是消息隊列的生命隨操作系統,所以當我們創建了一個新的消息隊列的話一定要手動的去銷燬,不然再次創建的話就有可能會失敗,那麼這我們介紹兩個命令
ipcs -q:查看所有的消息隊列
ipcrm -q id:刪除id的消息隊列

那現在我們知道創建消息隊列失敗的原因:
  1. 操作系統的消息隊列的數目已達上限
  2. 創建的此消息隊列的ID已被佔用


那我們用消息隊列來寫一個服務器和客戶端的相互通信
首先是關於消息隊列的一系列的函數
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 PATH_NAME "/tmp"
#define PROJ_ID 0x6666
//創建消息隊列
#define SERVER_TYPE 1
#define CLIENT_TYPE 2


//此時我們用msgbuf是顯示重定義
//應該是在頭文件裏的msg緩衝區定義爲msgbuf
//我們將我們的名字換一下即可
struct msgbuff
{
  long mtype;
  char mtext[128];
};

int createMsgQueue();
//創建消息隊列

int getMsgQueue();
//獲得消息隊列

int sendMsg(int msgid,char *msg,int t);
//發送消息隊列

//接受消息隊列
int recvMsg(int msgid,char *msg,int t);

//銷燬消息隊列
void destoryMsgQueue(int msgid);

#endif


comm.c
#include "comm.h"

int commMsgQueue(int flag)
{
  key_t k = ftok(PATH_NAME,PROJ_ID);
  if(k < 0)
  {
    printf("ftok error!!");
    return -1;
  }

  int msgid = msgget(k,flag);
  if(msgid < 0)
  {
    printf("msgget error!!");
    return -2;
  }
  return msgid;
}

int createMsgQueue()
{
  return commMsgQueue(IPC_CREAT|IPC_EXCL|0644);
}

int getMsgQueue()
{
  return commMsgQueue(IPC_CREAT);
}


void  destoryMsgQueue(int msgid)
{
  if(msgctl(msgid,IPC_RMID,NULL) < 0)
  {
    printf("msgctl error!!");
  }
}
//發送數據塊
//msgid(消息隊列的標識符),msg(數據塊結構體的地址),
//msgsz(數據塊裏數組的字節大小),msgflg(判斷是阻塞式還是非阻塞式)
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

int sendMsg(int msgid,char *msg,int t)
{
  struct msgbuff buf;
  buf.mtype = t;
  strcpy(buf.mtext,msg);
  if(msgsnd(msgid,&buf,sizeof(buf.mtext),0) < 0)
  {
    printf("msgsnd error!\n");
    return -1;
  }
  return 0;
}


//接收數據塊
//msgtyp(數據塊內容的類型)
//ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//msg:要發送的數據
int recvMsg(int msgid,char *msg,int t)
{
  struct msgbuff buf;
  if(msgrcv(msgid,&buf,sizeof(buf.mtext),t,0) < 0)
  {
    perror("msgrcv error!\n");
    return -1;
  }
  strcpy(msg,buf.mtext);
  return 0;
}



接下來是我們的服務器和客戶端的代碼


因爲服務器端是先接受消息,再發送消息
//server.c
#include"comm.h"

int main()
{
  int msgid = createMsgQueue();
  
  //printf("%d",msgid);
  char buf[256];
  while(1)
  {
    if(strcmp(buf,"quit") == 0)
    {
      printf("client quit\n");
      break;
    }
    recvMsg(msgid,buf,CLIENT_TYPE);
    printf("client #%s\n",buf);

    printf("Please enter:");
    scanf("%s",buf);
    sendMsg(msgid,buf,SERVER_TYPE);
  }
  destoryMsgQueue(msgid);
  return 0;
}


客戶端是先發送消息再接收消息
//client.c
#include"comm.h"

int main()
{
  int msgid = getMsgQueue();

  //先發消息
  char buf[256];

  while(1)
  {
    printf("Please enter :");
    scanf("%s",buf);

    sendMsg(msgid,buf,CLIENT_TYPE);

    if(strcmp("quit",buf) == 0)
    {
      printf("client quit!");
    }

    recvMsg(msgid,buf,SERVER_TYPE);
    printf("server #%s\n",buf);
  }

  destoryMsgQueue(msgid);

  return 0;
}



發佈了55 篇原創文章 · 獲贊 17 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章