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

原创 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进程间的通信(二)

一、死锁 (1) 死锁是指多个进程之间相互等待对方的资源,而在得到对方资源之前又不释放自己的资源,这样,造成循环等待的一种现象。如果所有进程都在等待一个不可能发生的事,则进程就死锁了。 ...

Linux进程间的通信(二)

简介: linux信号机制远远比想象的复杂,本文力争用最短的篇幅,对该机制做了深入细致的分析。读者可以先读一下信号应用实例(在信号(下)中),这样可以对信号发送直到相应的处理函数执行完毕这一过程有个大...

Chromium进程间的通信机制浅析(android版本)(二)

一、   初始化流程 每一个RenderProcessHostImpl(RenderProcessImpl)都会ChannelProxy(SyncChannel)—>ChannelProxy::Co...

nginx进程间的通信机制源码分析(二)-------原子操作、自旋锁、文件锁

原子操作 原子操作指的是由多步组成的一个操作.如果该操作原子的执行,则要么执行玩所有步骤,要么一步也不执行,不可能值执行所有步骤的一个子集. 想要使用原子擦操作来修改,获取整型变量,自然不能使用加减号...

进程间的通信(二)命名管道fifo

在linux下我们先通过一个实例来说明一下mkfifo 的作用, 然后再看mkfifo 的使用详解# mkfifo myfifo# pingedu.cn >> myfifo 另开一个终端:# cat ...

[Linux C编程]进程间的通信(二)

共享内存实现分为两个步骤: 1、创建共享、打开共享内存,使用shmget函数 2、映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数 3. 分离共享内存 4. 控制、...

进程间的互相通信问题

  • 2011年08月04日 12:15
  • 532B
  • 下载

vb 利用管道使进程间互相通信

Option   Explicit               Private   Declare   Function   CreatePipe   Lib   "kernel32"   (phRe...

进程间的通信--WM_COPYDATA

  • 2008年03月26日 10:03
  • 71KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:重新审视进程间的通信(二)
举报原因:
原因补充:

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