重新审视进程间的通信(二)

原创 2016年06月05日 23:04:04

在UNIX网络编程中有关消息队列的内容分两章,一章Posix标准,一章System V(包括之后的内容都是)。

先看System V。


struct msqid_ds
{
  struct ipc_perm msg_perm;	/* structure describing operation permission */
  __time_t msg_stime;		/* time of last msgsnd command */
#ifndef __x86_64__
  unsigned long int __glibc_reserved1;
#endif
  __time_t msg_rtime;		/* time of last msgrcv command */
#ifndef __x86_64__
  unsigned long int __glibc_reserved2;
#endif
  __time_t msg_ctime;		/* time of last change */
#ifndef __x86_64__
  unsigned long int __glibc_reserved3;
#endif
  __syscall_ulong_t __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() */
  __syscall_ulong_t __glibc_reserved4;
  __syscall_ulong_t __glibc_reserved5;
};

Unix98不要求有msg_first、msg_last、msg_cbytes成员(我也没找到)msg_first、msg_last两个指针指向内核,对于应用基本没用。


创建或者访问一个队列

#include <sys/msg.h>

int msgget(key_t key, int oflag);

返回值是一个整数标识符,代指该队列

key可以使ftok()的返回值或者常数IPC_PRIVATE

oflag读写权限组合值,还可与IPC_CREATE(key不存在创建,存在则引用)和IPC_CREAT | IPC_EXCL(key不存在创建,存在则出错)进行异或

当创建时,msg_perm中的uid和cuid成员被设置为当前进程有效用户ID,gid和cgid被设置当前进程的有效组ID


放置消息

#include <sys/msg.h>

int msgsnd(int msqid, const void *ptr, size_t length, int flag);

mspid是msgget的返回值


ptr是一个结构指针指向msgbuf,该结构没有定式,但是有一定要求

struct msgbug {
    long mtype;
    char data[1];
}

该结构必须以一个长整型变量(表示类型)开始和数据,其他的自己看着办。

length为自定义的数据大小。

flag 为0(如果没有新消息的可用空间则阻塞)或者IPC_NOWAIT(如果数据放不下则返回错误)


读消息

ssize_t msgrcv(int msgid, void *ptr, size_t length, long type, int flag);

ptr指向一个结构踢和msgsnd一样,length为缓冲区中数据大小(最多能返回的数据量)


type给定读出什么样的消息

为0,返回第一个消息(最早的消息)

大于0,返回类型值为type的第一个消息

小于0,返回类型值小于或等于type绝对值的消息中类型值最小的那个消息。

flag:IPC_NOWAIT如果没有所请求类型的消息则返回错误,否则阻塞

MSG_NOERROR如果数据长度大于length则截取不返回错误,否则返回E2BIG错误


控制操作

int msgctl(int msgid, int cmd, struct msqid_ds *buff);
IPC_RMID:删除指定队列

IPC_SET:给指定队列设置msqid_ds结构中msg_perm.uid、msg_perm.gid、msg_perm.mode和msg_qbytes

IPC_STAT:给调用者返回指定消息队列的msqid_ds


再看Posix消息队列


每个消息有如下属性:

1:一个无符号整数优先级(Posix)或长整数类型(System V)

2:数据部分长度

3:数据本身


创建新消息队列或打开一个队列

#include <mqueue.h>

mqd_t mq_open(const char *name, int oflag, .../*mode_t mode, struct attr *attr*/);
oflag标志位

O_RDONLY(只读) O_WRONLY(只写) O_RDWR(可读可写)可与以下异或

O_CREAT(创建) O_EXCL (当消息已存在时,返回EEXIST错误到errno中)O_NONBLOCK(设置非阻塞)

mode参数

S_IRUSR用户(属主)读

S_IWUSR用户(属主)读

S_IRGRP组成员读

S_IWGRP组成员写

S_IROTH其他用户读

S_IWOTH其他用户写

attr用于给新队列指定某些属性,NULL为默认属性

返回值为消息队列描述符

关闭

int mq_close(mqd_t mqdes);
很简单,当一个进程终止它所打开的消息队列都关闭,就像调用mq_close一样


int mq_unlink(const char *name);
每个消息队列都有一个保存当前打开着描述符数的引用计数器,当一个消息队列的引用计数大于0就可以用此函数删除name,该队列析构要到最后一个mq_close

消息队列属性

struct mq_attr

{

long int mq_flags;    /* Message queue flags0O_NONBLOCK */

long int mq_maxmsg;   /* Maximum number of messages.  */

long int mq_msgsize;  /* Maximum message size.  */

long int mq_curmsgs;  /* Number of messages currently queued.  */

long int __pad[4];

};

int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, const struct mq_attr *attr, struct mq_attr *oattr);

mq_setattr函数只使用attr指向的结构的mq_flags成员,对oattr指向的结构进行设置

如果oattr非空,则队列的先前属性和当前状态都返回到该数组中。


int mq_send(mqd_t mqdes, char *ptr, size_t len, unsigned int prio);
ssize_t mq_receiver(mqd_t mqdes, char *ptr, size_t len, unsigned int *priop);

发送和接收函数

mq_receive中的len不能小于能加到所指队列中的消息的最大大小(mq_msgsize成员)

mq_send函数中prio是待发送消息的优先级,其值必须小于MQ_PRIO_MAX

如果mq_recceive中的priop非空则用来保存返回消息的优先级。

Posix消息队列允许异步事件通知(asynchronous event notification),以告知何时有一个消息放置到了某个队列中。

int mq_notify(mqd_t mqdes, const struct sigevent *notification);

该函数通知进程何时可以接受一条消息

sigevent结构体

struct sigevent {
    int           sigev_notify;            //Notification type. 
    int           sigev_signo;            //Signal number. 
    union sigval  sigev_value;             //Signal value. 
    void         (*sigev_notify_function)(union sigval); //Notification function. 
    pthread_attr_t *sigev_notify_attributes;  //Notification attributes. 
};
 sigev_notify 的取值:

SIGEV_NONE 事件发生时,什么也不做. SIGEV_SIGNAL 事件发生时,将sigev_signo 指定的信号(A queued signal)发送给指定的进程. SIGEV_THREAD 事件发生时,内核会(在此进程内)以sigev_notification_attributes为线程属性创建一个线程,并且让它执行sigev_notify_function 传入sigev_value作为为一个参数.
union sigval
{
    int sival_int;
    void *sival_ptr;
};
mq_notify函数有一下适用规则

(1)如果notification参数非空,那么当前进程希望在有一个消息达到所指定的先前为空的队列时得到通知

(2)如果notification参数为空,而且当前进程目前被注册为接收所指定队列的通知,那么已存在的注册将被撤销

(3)任意时刻只有一个进程可以被注册为接收某个给定队列的通知

(4)当有一个消息到达某个先前为空的队列,而且已有一个进程被注册为接收该队列的通知时,只有在没有任何线程阻塞在该队列的mq_receive调用中的前提下,通知才会发出。mq_receive调用比任何通知的注册都优先。

(5)当该通知被发送给它的注册过程时,其注册即被注销。必须再次调用mq_notify以重新注册。


Posix消息队列和System V消息队列差别

(1)Posix消息队列总是返回优先级最高的最早消息,System V消息队列可以返回指定的任意消息;

(2)当往空队列中添加消息时,Posix消息队列允许产生一个信号或者启动一个线程。


PSSSSSSSSSSSS:为啥子CSDN博客总是无法正常显示呢,好尴尬。。。。修改几次了





版权声明:本文为博主原创文章,未经博主允许不得转载。

重新审视进程间的通信(一)

最近干活的时候又被Linux管道和消息队列搞的一脸懵逼。当初自己走马观花似的学习以为内容很简单,结果留下了大坑,借来Unix网络编程来补补,重新审视这两个部分,并且引以为戒!!! 首先看管道#incl...
  • protoss_penguin
  • protoss_penguin
  • 2016年06月01日 00:15
  • 1253

应该重新审视的javascript

或许这个话题相当有趣,只是因为Javascript会有一个新的增长,web是未来,Javascript也会有未来,当没有一个新的语言可以在web方面代替的时候。 强大的Javascript Java...
  • gmszone
  • gmszone
  • 2014年02月28日 20:35
  • 1992

用happen-before规则重新审视DCL

精华帖子:http://www.iteye.com/topic/260515; 编写Java多线程程序一直以来都是一件十分困难的事,多线程程序的bug很难测试,DCL(Double Check ...
  • working_brain
  • working_brain
  • 2014年11月11日 15:20
  • 576

由芬兰教育重新审视中国教育

很长一段时间,我对于中国教育遭到许多人抨击的理解是这样的:教育之失败是社会之失败的写照,社会对于教育的影响可以说是决定性的(当然,要说学校是社会的一部分也行)。逐利而浮躁的社会可能导致简单粗暴的教育,...
  • Greg_wangyang
  • Greg_wangyang
  • 2017年02月12日 10:02
  • 154

用happen-before规则重新审视DCL

转自:http://www.iteye.com/topic/260515 编写Java多线程程序一直以来都是一件十分困难的事,多线程程序的bug很难测试,DCL(Double Check Lock)...
  • myGinger
  • myGinger
  • 2015年07月30日 23:03
  • 367

正数(十进制)变二进制 除以2取余 小数(十进制)变二进制 乘以2取整数

十进制整数转二进制: 就是把该十进制数,用二因式分解,取余。 以12为例,转为二进制 2除以12得6,余0,取0 2除以6得3,余0,取0 2除以3得1,余1,取1 最后剩下1,由它开始写起,就可得...
  • qq_16485855
  • qq_16485855
  • 2016年06月14日 21:18
  • 311

重新审视网易:上势必然

当一个现象或者技术被广泛提及和接受之后,必定会引起脱离本质之外的喧嚣,超负荷的信息会掩盖人们认知事物本身的锚点。但是当浪潮退去,臃肿的信息从事物本身剥离的时候,我们更需要的,是客观理性的重新审视。 ...
  • sinat_32970179
  • sinat_32970179
  • 2017年02月16日 15:55
  • 188

用happen-before规则重新审视DCL

编写Java多线程程序一直以来都是一件十分困难的事,多线程程序的bug很难测试,DCL(Double Check Lock)就是一个典型,因此对多线程安全的理论分析就显得十分重要,当然这决不是说对多线...
  • dingjikerbo
  • dingjikerbo
  • 2017年03月16日 17:55
  • 279

为了编程梦想,重新审视自己,开始出发。

我是一个有梦想的人。而且,我的成功习惯可以帮助我实现梦想。所以,我不想把我伟大的精力花费在无谓的琐事上。我没有时间对小事犹豫。我想把自己全身上下的宝贵能量,用在实现自己的梦想上。...
  • u012272880
  • u012272880
  • 2015年04月29日 23:27
  • 522

身居乱世之中,重新审视“活法

《活法》稻盛和夫   “吾等定此血盟不为私利私欲,但求团结一致,为社会、为世人成就事业。特此聚合诸位同志,血印为誓。”   ——稻盛和夫   编者注:上面的话,是稻盛和夫先生在创业之初的...
  • u013256040
  • u013256040
  • 2014年01月21日 10:33
  • 2279
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:重新审视进程间的通信(二)
举报原因:
原因补充:

(最多只允许输入30个字)