进程间通信之消息队列

一、消息队列?
消息队列是个什么东东嘞?它其实就是有点像我们玩的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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值