进程间通信(二):消息队列

消息队列是操作系统为两个无关进程准备的通信方式,每个消息队列都有一个他自己的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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值