可以想象,如果两个进程都可以访问同一个队列:其中一个进程(sender)向其中写入结构化数据,另外一个进程(receiver)再从其中把结构化的数据读取出来。那么这两个进程就是在利用这个队列进行通信了,这个队列也就称为消息队列(message queue)。 

消息队列有system V和POSIX两种,这里说system V的。 

内核维护中很多个消息队列(因为有很多不同的进程要用它们来通信,不可能共享一个),我们使用一个key_t类型的key来让发送端和接收端进程都清楚了解自己使用的是哪个消息队列。 

key_t类型实际上就是一个int类型 

typedef int  __kernel_key_t; (查看这里) 

typedef __kernel_key_t  key_t; (查看这里) 

所以我们可以简单地想象成每个消息队列都有一个自己的唯一id。虽然直接为两个进程指定一个常数值(比如12345)作为你创建的消息队列的key一般是没有问题的,但为了保证唯一性和可读性,我们可以用ftok()函数来创建该key。 

key_t ftok(const char *path, int id); 

第一个参数是你指定的文件(或目录)路径,id是一个子序号,该函数将指定的文件路径对应的索引节点号和id结合起来生成一个key值,比如指定文件的索引节点号为56672,换算成16进制为0xDD60,而你指定的id值为52,换算成16进制为0x34,则最后的key_t返回值为0x3400DD60。 

我们可以通过msgget函数来创建一个新的消息队列或者取得已经存在的消息队列。 

int msgget(key_t key, int msgflg);

key参数: 

就是要新建或获取的消息队列的唯一标识,其一般是由上面的ftok函数成长的,但有一个例外是其还可以是一个叫做IPC_PRIVATE的值(实际上是值为0的key): 

#define IPC_PRIVATE ((__kernel_key_t) 0)  

当key为IPC_PRIVATE时,则msgget始终创建一个新的消息队列。 

msgflg参数: 

其有两层含义,一是该参数可以取值IPC_CREATE,表示请求msget函数新建消息队列;也可以是 IPC_CREATE|IPC_EXCL的按位组合,表示请求新建消息队列但如果队列已经存在的话则报错。二是该参数表示权限控制,比如666表示全部可读写。那么如果该参数写成IPC_CREATE|IPC_EXCL|666则表示请求新建消息队列但如果队列已经存在的话则报错并且权限为666 

与管道不一样,我们向消息队列中写入会从其中读取信息时采用的不是字节流而是按照某一约定的结构体,比如: 

struct msg 

{ 

long msg_type; 

char msg_txt[SIZE]; 

}; 

其第一个字段是一个长整形数,表示该信息的类型,这个字段可以让我们将不同“类型”的消息写入同一个管道,比如可以用1表示普通信息,用2表示错误信息。当读取端从消息队列中读取消息时,如果不指定类型(类型值为0)则其读取队列中的第一个消息,而如果指定了类型的话,则读取该类型的第一个消息(所以其并不完全地按照先入先出的顺序) 

后面的字段表示消息的内容部分,一般用一个字节数组,但其实是可以自定义的,比如: 

struct msg 

{ 

long msg_type; 

int  other_filed; 

char msg_txt[SIZE]; 

}; 

用msgsnd函数来发送消息到消息队列中去: 

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)

msgid参数: 

消息队列的id,也就是上面所说的key. 

msgp参数: 

指向消息结构体的指针 

msgsz参数: 

表示消息结构体的大小,由于消息结构体是可以自定义的,所以必须指定大小类分割连续的消息 

msgflg参数: 

这个参数主要用于如下情况:消息队列中的消息数目达到了系统上限 或 消息队列没有足够的空间来容纳消息字节。此时,如果指定了msgflg为IPC_NOWAIT的话(msgflg & IPC_NOWAIT != ),那么消息将不被发送,而函数直接返回。相反的(msgflg & IPC_NOWAIT == ),调用该函数的进程将会被挂起,直到下面三种情况之一发生: 

)上述两种情况不再满足,消息被发送 

)消息队列被系统移除,消息不被发送。 

)进程接收到信号转入进行信号处理,这种情况下,消息不会被发送。 

struct message {
long msg_type;
char msg_text[SIZE];
} msg;

msg.msg_type = ;
strcpy(msg.msg_text, "This is message 1");
...
result = msgsnd(msqid, (void *) &msg, sizeof(msg.msg_text), IPC_NOWAIT); 相对应的,msgrcv函数用来从消息队列中读取消息: ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); msgtyp参数: 如果该值为0,则读取消息队列中的第一个消息 如果该值大于0,则读取消息队列中具有指定类型的第一个消息 如果该值小于0,则读取消息队列中类型值小于或等于指定值的绝对值的最小类型值的第一个消息(好晕,the first message of the lowest type that is less than or equal to the absolute value of msgtyp) msgflg参数: 这个参数主要用于消息队列中当没有消息(或指定类型的消息)可供读取时,如果指定了msgflg为IPC_NOWAIT的话(msgflg & IPC_NOWAIT != ),函数将直接返回而放弃读取。相反的(msgflg & IPC_NOWAIT == ),调用该函数的进程将会被挂起,直到下面三种情况之一发生: )有消息到来,可读取了 )消息队列被系统移除,放弃消息读取 )进程接收到信号转入进行信号处理,放弃消息读取 msgflg也可以指定如下操作: /* msgrcv options */ #define MSG_NOERROR 010000 /* no error if message is too big */ #define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/ 另外还有一个msgctl函数可以对消息队列进行一些其他控制和读取消息队列的属性消息,不过在这之前需要先了解下消息队列本身的数据结构msqid_ds: struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; /* first message in queue, unused */
struct msg *msg_last; /* last message in queue, unused */
__kernel_time_t msg_stime; /* last msgsnd time */
__kernel_time_t msg_rtime; /* last msgrcv time */
__kernel_time_t msg_ctime; /* last change time */
unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */
unsigned long msg_lqbytes; /* ditto */
unsigned short msg_cbytes; /* current number of bytes on queue */
unsigned short msg_qnum; /* number of messages in queue */
unsigned short msg_qbytes; /* max number of bytes on queue */
__kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */
__kernel_ipc_pid_t msg_lrpid; /* last receive pid */
};
其中msg_perm字段表示消息队列的所有者和权限信息:
struct ipc_perm
{
__kernel_key_t key;
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode;
unsigned short seq;
}; msg_qbytes表示消息队列所能容纳的最大消息字节数。 再来看看msgctl函数: int msgctl(int msqid, int cmd, struct msqid_ds *buf); cmd参数: 表示要对消息队列执行的操作,可以有如下三种: )IPC_STAT获取消息队列属性信息,并将这些信息放置到第3个参数所设置的buffer中 )IPC_SET 根据buffer中的数据设置消息队列的一些属性,并非所有属性都可设置,其仅仅限于:msg_perm.uid,msg_perm.gid,msg_perm.mode,msg_qbytes 这几种 )IPC_RMID 删除消息队列。 注:IPC_SET和IPC_RMID都会进行相应的权限检查,只有具备权限的进程才能执行相关操作

linux 进程学习笔记-消息队列messagequeue的更多相关文章

  1. linux进程学习笔记

    学习了linux下的进程,觉得应该整理一下,忘得差不多了,顺便回顾一下. 学而时习之,不亦说乎~~ 进程笔记 ,什么是进程? The Single UNIX Specification, Versio ...

  2. linux进程通信:消息队列

    消息队列可以实现两个没有关系的进程之间的通信. 创建了一个消息队列后,进程可以往里面放消息,也可以取消息.因为这个消息队列是有名字的,所以就算是两个没有关系的进程,也能通信. 而且人性化的一点是,可以 ...

  3. linux 进程学习笔记-进程pipe管道

    所谓“进程间通信(IPC,inter-process communication)”,按照其目的讲就是让进程之间能够“共享数据”,“传输数据”,“事件通知”等,我所知道的一共有“管道” “信号” “消 ...

  4. linux 进程学习笔记-共享内存

    如果能划定一块物理内存,让多个进程都能将该内存映射到其自身虚拟内存空间的话,那么进程可以通过向这块内存空间读写数据而达到通信的目的.另外,和消息队列不同的是,共享的内存在用户空间而不是核空间,那么就不 ...

  5. linux 进程学习笔记-进程状态

    task_struct的state字段记录的进程的状态,可分为如下几种: #define TASK_RUNNING 0 可运行状态.这是 “进程正在被CPU运行” 和 “进程正在可运行队列中等待被CP ...

  6. linux 进程学习笔记-进程调度

    在分时系统中,系统将CPU时间划分成无数个时间片(quantum)分配给不同的进程,一个时间片只执行一个进程,并且不停地切换,以让用户感觉到各个进程是在“同时运行”,这中间所需要的策略和算法便是进程调 ...

  7. linux 进程学习笔记-进程信号sigal

    信号(或软中断)是在软件层次上对中断的一个模拟,其运行在“用户空间”,一个进程对另外一个或几个进程通过发送信号来实现异步通信.当接收进程接收到信号后,其可以注册一下处理函数来说对这些信号进行处理(也可 ...

  8. Linux 进程学习笔记

    1.什么是程序?什么是进程?它们有什么区别? 定义: 程序:程序(Program)是一个静态的命令集合,程序一般放在磁盘中,然后通过用户的执行来触发.触发后程序会加载到内存中成为一个个体,就是进程. ...

  9. linux 进程学习笔记-进程ID,PID

    PID,进程号 , 范围在2~(??为什么需要这么多),而一个名为idle (或swapper)的进程占据的编号0,init进程占据了编号1. 进程0和进程1 : 系统启动时会从无到有地创建进程0,它 ...

随机推荐

  1. ubuntu下编译原生ffmpeg

    本文主要介绍Linux 系统下如何编译Ffmpeg,编译环境是Ubuntu 16.04,Ffmpeg版本是3.4.2.Windows环境 下如何编译ffmpeg前面有博文介绍,也录有视频,感兴趣的同学 ...

  2. 在 Selenium 中让 PhantomJS 执行它的 API

    from selenium import webdriver driver = webdriver.PhantomJS() script = "var page = this; page.o ...

  3. win10多用户远程登录

    实现效果:不同的电脑可以同时登录一台windows主机,但是必须使用不同的账号 首先,我们来创建一个新用户 点击设置,搜索用户 点击下一步,一个普通用户就创建完成了. 然后,打开远程设置,右键此电脑, ...

  4. sudo apt-get update 没有公钥,无法验证下列签名

    在更新系统源后,输入sudo apt-get update之后出现提示: W: GPG 错误:http://archive.ubuntukylin.com:10006 xenial InRelease ...

  5. 使用Chrome(PC)调试移动设备上的网页

    最早开始调试移动端网页时,本人都是采取PC上改几行代码,手机上刷新一下看效果这种笨方法来开发的,效率低而且容易让人抓狂.最近偶然发现原来可以使用PC上的浏览器来调试移动设备,不由得感叹相逢恨晚. 工具 ...

  6. Chrome自带恐龙小游戏的源码研究(二)

    在上一篇<Chrome自带恐龙小游戏的源码研究(一)>中实现了地面的绘制和运动,这一篇主要研究云朵的绘制. 云朵的绘制通过Cloud构造函数完成.Cloud实现代码如下: Cloud.co ...

  7. 设置jvm运行内存

    :1.右击项目—Bulid Path—Configure Build Path—Libraries,找到JRE System Libraary[Sun JDK 1.6.0_13],选中JRE Syst ...

  8. A和B是好友,他们经常在空闲时间聊天,A的空闲时间为[a1 ,b1 ],[a2 ,b2 ]..[ap ,bp ]。B的空闲时间是[c1 +t,d1 +t]..[cq +t,dq +t],这里t为B的起床时间。这些时间包括了边界点。B的起床时间为[l,r]的一个时刻。若一个起床时间能使两人在任意时刻聊天,那么这个时间就是合适的,问有多少个合适的起床时间?

    // ConsoleApplication5.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<vector> ...

  9. 彻底隐藏Nginx版本号的安全性与方法

    Nginx默认是显示版本号的,如: [root@bkjz ~]# curl -I www.nginx.orgHTTP/1.1 200 OKServer: nginx/0.8.44Date: Tue, ...

  10. vsftpd 虚拟用户限定在虚拟用户目录

    1.安装vsftpd yum -y install pam pam-devel db4 db4-tcl vsftpd 2.更名默认配置文件,以便恢复 cp /etc/vsftpd/vsftpd.con ...