前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >进程间通讯(五).message queue(2)

进程间通讯(五).message queue(2)

作者头像
franket
发布2021-09-15 20:20:53
7710
发布2021-09-15 20:20:53
举报
文章被收录于专栏:技术杂记技术杂记

msgqueB.c

代码语言:javascript
复制
#include <stdio.h>
#include <sys/msg.h> //key_t,ftok,msgget,msgrcv,msgctl,IPC_RMID 相关声明在这个头文件中有所包含
#include <string.h> //memset,strcmp 相关函数声明在这个头文件中有所包含
#define BUFSZ 1024


typedef struct message  //此结构体用于存放消息,从中可以看到消息的两个字段
{
  long msg_type; //消息类型,以整型值进行标示
  char msg_text[BUFSZ]; //消息内容体
}MSG; //取了一个别名

int main()
{
  int res=-1,qid=0;
  key_t key=IPC_PRIVATE;  //IPC_PRIVATE 就是0
  MSG msg;
  
  if(-1 == (key=ftok("/",18))) //调用ftok使用相同的参数生成key,用于获取一样的队列ID
  {
    perror("ftok");
    return res;
  }
  if(-1==(qid=msgget(key,IPC_CREAT|0600))) //创建一个消息队列,将id存到qid中(如果已经存在,则获取它的ID)
  {
    perror("msgget");
    return res;
  }
  printf("open queue %d\n",qid);
  
  do
  {
    memset(msg.msg_text,0,BUFSZ); //将msg.msg_text的内容清零
    if(0 > msgrcv(qid,&msg,BUFSZ,0,0)) //从消息队列中获取信息并且存到msg中
    {
      perror("msgrcv");
      return res;
    } 
    printf("the message from process %ld is %s",msg.msg_type,msg.msg_text); //将信息内容在终端进行打印
  }while(strcmp(msg.msg_text,"quit\n")); //如果内容为quit就进行跳出
  

   if( 0 > msgctl(qid,IPC_RMID,NULL) ) //将队列删除,如果不删除,在进程退出后,消息将依旧保留在内核中,直到重启系统,消息的持久性,界于进程与磁盘之间
   {
     perror("msgctl");
     return res;
   }
  res=0;
  return res;
}

编译执行

代码语言:javascript
复制
emacs@ubuntu:~/c$ alias gtc
alias gtc='gcc -Wall -g -o'
emacs@ubuntu:~/c$ gtc  msgqueA.x msgqueA.c ; gtc msgqueB.x msgqueB.c
emacs@ubuntu:~/c$ 

执行 msgqueB.x 会等待输入

代码语言:javascript
复制
emacs@ubuntu:~/c$ ./msgqueB.x 
open queue 98304

执行 msgqueA.x 会等待输入

代码语言:javascript
复制
emacs@ubuntu:~/c$ ./msgqueA.x 
open queue 98304
please enter the message to queue:
(message start with 'START' will be valid,'quit' to exit)

msgqueA.x 端输入一些内容

代码语言:javascript
复制
emacs@ubuntu:~/c$ ./msgqueA.x 
open queue 98304
please enter the message to queue:
(message start with 'START' will be valid,'quit' to exit)
STARTtest
please enter the message to queue:
(message start with 'START' will be valid,'quit' to exit)
123
please enter the message to queue:
(message start with 'START' will be valid,'quit' to exit)
START123
please enter the message to queue:
(message start with 'START' will be valid,'quit' to exit)
quit
emacs@ubuntu:~/c$

msgqueB.x 端会进行显示

代码语言:javascript
复制
emacs@ubuntu:~/c$ ./msgqueB.x 
open queue 98304
the message from process 23670 is STARTtest
the message from process 23670 is START123
the message from process 23670 is quit
emacs@ubuntu:~/c$ 

编译执行过程中没有报错,从结果来看,符合预期


ftok

此函数的原型在 sys/ipc.h

代码语言:javascript
复制
/* Generates key for System V style IPC.  */
extern key_t ftok (__const char *__pathname, int __proj_id) __THROW;

The ftok function uses the identity of the file named by the given pathname (which must refer to an existing, accessible file) and the least significant 8 bits of proj_id (which must be nonzero) to generate a key_t type System V IPC key

此函数把从pathname导出的信息与id的低序8位组合成一个整数IPC键


key_t

代码语言:javascript
复制
emacs@ubuntu:/usr/include$ grep key_t sys/ipc.h
#ifndef __key_t_defined
typedef __key_t key_t;
# define __key_t_defined
extern key_t ftok (__const char *__pathname, int __proj_id) __THROW;
emacs@ubuntu:/usr/include$ grep key_t bits/types.h
__STD_TYPE __KEY_T_TYPE __key_t;	/* Type of an IPC key.  */
emacs@ubuntu:/usr/include$ grep __KEY_T_TYPE  bits/typesizes.h
#define __KEY_T_TYPE		__S32_TYPE
emacs@ubuntu:/usr/include$ grep __S32_TYPE bits/types.h
#define	__S32_TYPE		int
emacs@ubuntu:/usr/include$

可知 key_t 其实就是 int

key_t <= __KEY_T_TYPE <= __S32_TYPE <= int


IPC_PRIVATE

bits/ipc.h 中有关于 IPC_X 的宏定义

代码语言:javascript
复制
/* Mode bits for `msgget', `semget', and `shmget'.  */
#define IPC_CREAT       01000           /* Create key if key does not exist. */
#define IPC_EXCL        02000           /* Fail if key exists.  */
#define IPC_NOWAIT      04000           /* Return error on wait.  */

/* Control commands for `msgctl', `semctl', and `shmctl'.  */
#define IPC_RMID        0               /* Remove identifier.  */
#define IPC_SET         1               /* Set `ipc_perm' options.  */
#define IPC_STAT        2               /* Get `ipc_perm' options.  */
#ifdef __USE_GNU
# define IPC_INFO       3               /* See ipcs.  */
#endif

/* Special key values.  */
#define IPC_PRIVATE     ((__key_t) 0)   /* Private key.  */

所以 IPC_PRIVATE 其实代表的是 0


msg.h 所包含的头文件

代码语言:javascript
复制
emacs@ubuntu:/usr/include$ grep include sys/msg.h 
#include <features.h>
#include <stddef.h>
#include <sys/ipc.h>
#include <bits/msq.h>
#include <time.h>
emacs@ubuntu:/usr/include$ grep include sys/ipc.h 
#include <features.h>
#include <bits/ipctypes.h>
#include <bits/ipc.h>
emacs@ubuntu:/usr/include$

msgget

msgget 的原型定义在 sys/msg.h

代码语言:javascript
复制
/* Get messages queue.  */
extern int msgget (key_t __key, int __msgflg) __THROW;

__msgflg 是读写权限的组合,相关的宏在 bits/ipc.h 中有所定义

返回值为一个整型,即消息队列的ID


msgsnd

msgsnd 的原型定义在 sys/msg.h

代码语言:javascript
复制
/* Send message to message queue.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int msgsnd (int __msqid, __const void *__msgp, size_t __msgsz,
                   int __msgflg);

__msqid 消息队列的ID

__msgp 消息结构体的指针

__msgsz 消息内容的长度

__msgflg 控制函数行为的标志 , 一般取0 , 表示忽略


msgrcv

msgrcv 的原型定义在 sys/msg.h

代码语言:javascript
复制
/* Receive message from message queue.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t msgrcv (int __msqid, void *__msgp, size_t __msgsz,
                       long int __msgtyp, int __msgflg);

__msqid 消息队列的ID

__msgp 消息结构体的指针

__msgsz 消息内容的长度

__msgtyp 消息类型,可以实现一种简单的接收优先级

如果 msgtype == 0,就获取队列中的第一个消息 如果 msgtype > 0,将获取具有相同消息类型的第一个信息 如果 msgtype < 0,就获取类型等于或小于msgtype的绝对值的第一个消息

__msgflg

这个参数依然是是控制函数行为的标志,取值可以是:0,表示忽略;IPC_NOWAIT,如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件的消息为止。如果一个client 正在等待消息的时候队列被删除,EIDRM 就会被返回。如果进程在阻塞等待过程中收到了系统的中断信号,EINTR 就会被返回。MSG_NOERROR,如果函数取得的消息长度大于msgsz,将只返回msgsz 长度的信息,剩下的部分被丢弃了。如果不指定这个参数,E2BIG 将被返回,而消息则留在队列中不被取出。当消息从队列内取出后,相应的消息就从队列中删除了。

函数调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msgp指向的用户分配的缓存区中,然后删除消息队列中的对应消息; 失败时返回-1


msgctl

msgctl 的原型定义在 sys/msg.h

代码语言:javascript
复制
/* Message queue control operation.  */
extern int msgctl (int __msqid, int __cmd, struct msqid_ds *__buf) __THROW;

__msqid 消息队列的ID

__cmd 将要采取的动作

bits/ipc.h 中有关于 IPC_X 的宏定义

代码语言:javascript
复制
#define IPC_RMID        0               /* Remove identifier.  */ //删除消息队列
#define IPC_SET         1               /* Set `ipc_perm' options.  */ // 如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值 
#define IPC_STAT        2               /* Get `ipc_perm' options.  */ //把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值

__buf msqid_ds 结构体指针

对删除消息队列的处理不是很完善,因为每个消息队列没有维护引用计数(打开文件有这种计数器),所以在队列被删除以后,仍在使用这一队列的进程在下次对队列进行操作时会出错返回

函数成功时返回0,失败时返回-1


msqid_ds

bits/msq.h 中有关于 msqid_ds 的定义

代码语言:javascript
复制
/* Structure of record for one message inside the kernel.
   The type `struct msg' is opaque.  */
struct msqid_ds
{
  struct ipc_perm msg_perm;	/* structure describing operation permission */
  __time_t msg_stime;		/* time of last msgsnd command */
#if __WORDSIZE == 32
  unsigned long int __unused1;
#endif
  __time_t msg_rtime;		/* time of last msgrcv command */
#if __WORDSIZE == 32
  unsigned long int __unused2;
#endif
  __time_t msg_ctime;		/* time of last change */
#if __WORDSIZE == 32
  unsigned long int __unused3;
#endif
  unsigned long int __msg_cbytes; /* current number of bytes on queue */
  msgqnum_t msg_qnum;		/* number of messages currently on queue */
  msglen_t msg_qbytes;		/* max number of bytes allowed on queue */
  __pid_t msg_lspid;		/* pid of last msgsnd() */
  __pid_t msg_lrpid;		/* pid of last msgrcv() */
  unsigned long int __unused4;
  unsigned long int __unused5;
};

ipc_perm

bits/ipc.h 中有关于 ipc_perm 的定义

代码语言:javascript
复制
/* Data structure used to pass permission information to IPC operations.  */
struct ipc_perm
  {
    __key_t __key;			/* Key.  */
    __uid_t uid;			/* Owner's user ID.  */
    __gid_t gid;			/* Owner's group ID.  */
    __uid_t cuid;			/* Creator's user ID.  */
    __gid_t cgid;			/* Creator's group ID.  */
    unsigned short int mode;		/* Read/write permission.  */
    unsigned short int __pad1;
    unsigned short int __seq;		/* Sequence number.  */
    unsigned short int __pad2;
    unsigned long int __unused1;
    unsigned long int __unused2;
  };

Tip: 消息队列原来的实施目的是提供高于一般速度的IPC,但现在与其它形式的IPC相比,在速度方面已经没有什么差别了,考虑到使用消息队列可能带来的问题,在新的应用程序中不应当再使用它们


fgets

stdio.h 中有关于 fgets 的原型声明

代码语言:javascript
复制
/* Get a newline-terminated string of finite length from STREAM.

   This function is a possible cancellation point and therefore not
   marked with __THROW.  */
extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
     __wur;

总结

以下函数可以进行有名管道的创建和信号的控制

  • ftok
  • msgget
  • msgsnd
  • msgrcv
  • msgctl

通过各方面资料弄懂其参数的意义和返回值的类型,是熟练掌握的基础

原文地址http://soft.dog/2017/01/23/c-ipc-messagequeue/

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 编译执行
  • ftok
  • key_t
  • IPC_PRIVATE
  • msg.h 所包含的头文件
  • msgget
  • msgsnd
  • msgrcv
  • msgctl
  • msqid_ds
  • ipc_perm
  • fgets
  • 总结
相关产品与服务
消息队列 CMQ 版
消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档