posix消息队列使用全面介绍
- 格式:docx
- 大小:34.53 KB
- 文档页数:12
LDAP(Lightweight Directory Access Protocol)是一种用于访问和维护分布式目录服务的协议。
在LDAP中,posixGroup是一种对象类(object class),用于表示包含一组用户的群组。
posixGroup可以用于管理用户和组的身份和权限。
要使用posixGroup,首先需要在LDAP目录中定义一个posixGroup对象。
下面是一个典型的posixGroup对象的LDIF(LDAP Data Interchange Format)示例:```dn: cn=mygroup,ou=groups,dc=example,dc=comobjectClass: topobjectClass: posixGroupcn: mygroupgidNumber: 10000memberUid: user1memberUid: user2```在这个示例中,我们创建了一个名为mygroup的posixGroup对象。
它具有以下属性:- `cn`:群组的通用名称(Common Name)- `objectClass`:对象类,必须包含posixGroup- `gidNumber`:群组的GID(Group ID)- `memberUid`:属于该群组的用户的用户名要使用posixGroup对象,可以执行以下操作:1. 创建posixGroup对象:使用适当的LDAP客户端工具(如ldapadd)将上述示例LDIF导入到LDAP目录中,以创建posixGroup对象。
2. 添加用户到posixGroup:修改posixGroup对象的`memberUid`属性,将用户添加为群组成员。
3. 查询posixGroup对象:使用适当的LDAP查询工具(如ldapsearch),根据需要检索posixGroup对象的属性和成员信息。
4. 删除posixGroup对象:使用适当的LDAP客户端工具,删除posixGroup对象及其相关属性。
进程间通信 IPC interprocess communication1,管道,FIFO2, 信号3,消息队列4,共享类存5.文件映射6.socket(1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。
(2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
命名管道在文件系统中有对应的文件名。
命名管道通过命令mkfifo或系统调用mkfifo来创建。
(3)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。
(4)消息(Message)队列:消息队列是消息的链接表,包括Posix消息队列system V 消息队列。
有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。
消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺(5)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。
是针对其他通信机制运行效率较低而设计的。
往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
(6)内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
(7)信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
(8)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。
POSIX消息队列是linux进程间通信的重要方式,下面按照创建,使用,关闭的顺序讲述了POSIX消息队列的使用方法:创建POSIX消息队列:mq_open#include<mqueue.h>mqd_t mq_open(const char *name,int oflag,int mode,mq_addr *attr);参数说明:Name:消息队列的名字字符串,必须以’/’开头,否则会出错。
Oflag: 表示打开的方式,1.首先必须说明读写方式,可以使以下的值之一:O_RDONLY:建立的队列是只读的O_WRONLY:建立的队列是只写的O_RDWR:建立的队列是可读可写2.必须有O_CREATE,说明是创建消息队列。
3.还有可选的选项:O_NONBLOCK:说明在创建的队列上发送和接收消息时,如果没有资源,不会等待,之间返回,如果不设置这个选项,缺省是会等待。
O_EXCL:在创建队列时,检测要创建的队列的名字是否已经存在了,如果已存在,函数会返回出错可以以或的方式形成Oflag,例如:O_RDWR|O_CREAT|O_EXCL Mode:是一个可选参数,在oflag中含有O_CREA T标志且消息队列不存在时,才需要提供该参数。
表示默认的访问权限,这个权限和文件访问的权限是相同的,取值也相同。
Mode可以由多个值组合而成,如:S_IRUSR|S_IWUSR,队列的所有者有读和写的权限。
Attr:指向结构struct mq_attr的指针。
我们可以在创建队列时通过这个结构设置队列的最大消息数和每个消息的最大长度。
struct mq_attr{long mq_flags; // 0或者O_NONBLOCK,说明是否等待long mq_maxmsg; //队列中包含的消息数的最大限制数long mq_msgsize; //每个消息大小的最大限制数long mq_curmsgs; //当前队列中的消息数}mq_maxmsg和mq_msgsize属性只能在创建消息队列时通过mq_open来设置。
消息队列的使用方法消息队列是一种用于在不同的系统和应用程序之间传递和传输数据的中间件。
它使用先入先出(FIFO)的方式存储和分发消息,可以提高系统的可靠性、扩展性和性能。
在实际应用中,消息队列有着广泛的使用场景,包括异步处理、解耦系统组件、削峰填谷、流量控制以及实现可靠的消息传递等。
下面将详细介绍消息队列的使用方法。
1.选择消息队列在开始使用消息队列之前,需要根据实际需求选择适合的消息队列。
常见的消息队列有Kafka、RabbitMQ和ActiveMQ等。
选择时,需要考虑消息的延迟要求、系统的可用性、消息吞吐量等因素。
2.定义消息格式在使用消息队列之前,需要定义消息的格式。
消息的格式应该简洁清晰,包含必要的信息,并考虑消息的扩展性和兼容性。
可以使用JSON、XML或者自定义的消息格式。
3.创建消息生产者消息生产者负责生成和发送消息到消息队列。
在创建消息生产者时,需要指定消息队列的地址和端口,并进行身份验证(如果需要)。
然后,通过消息队列提供的API,将消息发送到指定的队列中。
4.创建消息消费者消息消费者用于接收处理消息队列中的消息。
消费者需要连接到消息队列,并订阅一个或多个队列。
通过注册回调函数,消费者可以在消息到达时对消息进行处理。
5.异步处理消息一般情况下,消息队列的主要优势在于它可以实现异步处理。
消息生产者发送消息之后,可以立即返回,而不需要等待消息被消费者处理。
这种异步处理方式可以提高系统的性能和吞吐量。
6.解耦系统组件消息队列可以将系统中的各个组件解耦,使得它们可以独立运行和扩展。
消息生产者和消费者不需要直接知道对方的存在,它们只需要连接到消息队列即可。
7.削峰填谷消息队列可以用于平滑处理系统中的峰值流量。
当流量高峰到来时,消息队列可以暂时保存消息,等到系统负载下降时再进行消费。
这样可以避免系统因流量突增而崩溃。
8.流量控制通过设置合适的缓冲区大小和消费速率,消息队列可以实现流量控制。
mq_notify 是POSIX 消息队列库中的一个函数,它用于实现异步事件通知。
这个函数告诉POSIX 消息队列系统在某个空队列中放置了一个消息时产生一个信号或者创建一个线程来执行特定程序。
以下是mq_notify 的基本用法:
```c
#include <mqueue.h>
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
```
其中,mqdes 是消息队列的描述符,notification 是一个指向sigevent 结构的指针,用于指定当一个消息到达时需要执行的操作。
sigevent 结构至少包含以下字段:
* sigev_notify :指定通知类型,可以为SIGEV_NONE、SIGEV_SIGNAL 或SIGEV_THREAD。
* sigev_signo :当通知类型为SIGEV_SIGNAL 时,这个字段指定了发送的信号。
* sigev_value :当通知类型为SIGEV_SIGNAL 或SIGEV_THREAD 时,这个字段指定了传递给处理函数或线程的参数。
* sigev_notify_function :当通知类型为SIGEV_THREAD 时,这个字段指定了被调用的函数。
该函数应返回一个int 值。
* sigev_notify_attributes :当通知类型为SIGEV_THREAD 时,这个字段指定了被调用函数的线程属性。
以上信息仅供参考,建议阅读POSIX 消息队列官方文档以获取更全面和准确的信息。
QNX中的进程间通信(IPC)在QNX Neutrino中消息传递(Message passing)是IPC的主要形式,其他形式也都是基于消息传递来实现的。
QNX中提供了如下一个形式的IPC:Serive: Implemented in:・Message-passing Kernel・Signals Kernel・POSIX message queues External process・Shared memory Process manager・Pipes External process・FIFOs External process一、Synchronous message passing[同步消息传递]如果一个线程执行了MsgSend()方法向另一个线程(可以属于不同进程)发送消息,它会就被阻塞,直到目标线程执行了MsgReceive(),并处理消息,然后执行了MsgReply()。
如果一个线程在其他线程执行MsgSend()之前执行了MsgReceive(),它会被阻塞直到另一个线程执行了MsgSend()。
消息传递是通过直接的内存copy来实现的。
需要巨大消息传递的时候建议通过Shared Message[共享内存]或其他方式来实现。
1、消息传递中的状态迁移客户程序的状态迁移・SEND blocked:调用MsgSend()后,服务程序没有调用MsgReceive()的状态。
・REPLY blocked:调用MsgSend()后,并且服务程序调用了MsgReceive(),但是没有调用MsgReply()/MsgError()的状态。
当服务程序已经调用了MsgReceive()方法是,客户程序一旦调用MsgSend()就直接迁移如REPLY blocked状态。
・READY:调用MsgSend()后,并且服务程序调用了MsgReceive()和MsgReply()的状态。
服务程序的状态迁移:・RECEIVE blocked;调用MsgReceive()后,客户程序没有调用MsgSend()时的状态。
消息队列消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点。
作为早期unix通信机制之一的信号能够传送的信息量有限,后来虽然POSIX 1003.1b在信号的实时性方面作了拓广,使得信号在传递信息量方面有了相当程度的改进,但是信号这种通信方式更像"即时"的通信方式,它要求接受信号的进程在某个时间范围内对信号做出反应,因此该信号最多在接受信号进程的生命周期内才有意义,信号所传递的信息是接近于随进程持续的概念(process-persistent),见附录1;管道及有名管道及有名管道则是典型的随进程持续IPC,并且,只能传送无格式的字节流无疑会给应用程序开发带来不便,另外,它的缓冲区大小也受到限制。
消息队列就是一个消息的链表。
可以把消息看作一个记录,具有特定的格式以及特定的优先级。
对消息队列有写权限的进程可以向中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。
消息队列是随内核持续的(参见附录1)。
目前主要有两种类型的消息队列:POSIX消息队列以及系统V消息队列,系统V消息队列目前被大量使用。
考虑到程序的可移植性,新开发的应用程序应尽量使用POSIX消息队列。
在本系列专题的序(深刻理解Linux进程间通信(IPC))中,提到对于消息队列、信号灯、以及共享内存区来说,有两个实现版本:POSIX的以及系统V的。
Linux内核(内核2.4.18)支持POSIX信号灯、POSIX共享内存区以及POSIX消息队列,但对于主流Linux发行版本之一redhad8.0(内核2.4.18),还没有提供对POSIX进程间通信API的支持,不过应该只是时间上的事。
因此,本文将主要介绍系统V消息队列及其相应API。
在没有声明的情况下,以下讨论中指的都是系统V消息队列。
一、消息队列基本概念1.系统V消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。
测试三(优先级翻转)所有配置的优先级翻转测试结果在图九中显示。
除了Lynx(lsem)案例的所有案例中,低优先级和高优先级任务共享一个用于保护资源的pthread互斥量。
没有负载的情况下,第一个Lynx配置的延迟时间与中优先级任务的延迟时间10毫秒有对应关系。
这说明了一个事实,LynxOS 3.0.1中,没有为pthread互斥量实现优先级继承。
Lynx信号量没有这个问题。
Solaris中实现了优先级继承,没有负载情况下,所有Solaris配置的延迟时间都比较低。
高负载情况下,只有Lynx(lsem)和Solaris(1 rt)配置显示了可接收的延迟时间。
Solaris 1rt和2 proc配置都受到了高负载的影响;因为缺乏优先级继承协议,Lynx配置仍然具有高延迟时间。
上下文切换时间。
表九显示了所有平台的上下文切换时间,从头两个同步测试中的内存信号量结果计算而来。
Lynx上下文切换时间比最好的Solaris配置下的时间的一半还少。
同样,Lynx的进程到进程上下文切换时间只稍微比线程到线程切换时间长一点。
Solaris线程上下文切换时间比进程切换时间确定得多。
Solaris(1 rt)配置下,最大线程到线程切换时间接近平均值。
然而,同样配置下,进程到进程切换时间比平均值差了一个数量级。
另一个有趣的发现是,Solaris下进程间切换时间比线程间切换时间还稍微好一些。
两种情况下,都存在LWP间的上下文切换,似乎说明了系统开销的bulk 在调度器中。
通信实时信号图十显示了所有配置下的实时信号benchmark结果。
Lynx配置比任何Solaris配置的信号延迟时间都小。
并且,Solaris 1 proc和Solaris 2 proc配置都被增加的非实时负载严重影响。
消息队列所有配置的POSIX消息队列延迟时间和吞吐量在表十中显示。
Lynx平台的延迟时间比Solaris平台好,但是Solaris 平台的吞吐量更好。
php-amqplib 是一个基于 PHP 的 AMQP 库,用于与 RabbitMQ 通信。
它提供了简单而强大的 API,使得在 PHP 应用中使用消息队列变得更加轻松和可靠。
在本文中,我们将介绍 php-amqplib 的基本用法,包括安装、连接、发送和接收消息等操作。
一、安装 php-amqplib1. 使用 Composer 进行安装要使用php-amqplib,首先需要在项目中使用Composer 进行安装。
在项目根目录下创建一个poser.json 文件,并添加以下内容:```json{"require": {"php-amqplib/php-amqplib": "^2.9"}}```然后在命令行中执行以下命令安装 php-amqplib:```bashcomposer install```2. 手动安装如果不使用 Composer,也可以手动安装 php-amqplib。
首先从GitHub 上下载最新的代码包,并解压到项目中。
然后在代码中使用require_once 导入 php-amqplib 的 autoloader:```phprequire_once 'path/to/php-amqplib/autoload.php';```二、连接到 RabbitMQ1. 创建连接使用 php-amqplib 连接到 RabbitMQ 非常简单。
首先创建一个连接对象,并指定 RabbitMQ 的主机名、端口号、用户名和密码:```php$connection = new\PhpAmqpLib\Connection\AMQPStreamConnection('localhost', 5672, 'guest', 'guest');```2. 创建通道连接成功后,需要创建一个通道对象,用于在 RabbitMQ 中进行消息的发布和接收操作:```php$channel = $connection->channel();```三、发送消息1. 定义交换机和队列在发送消息之前,需要先定义交换机和队列。
`msgsnd` 是POSIX 消息队列中的一个函数,用于将消息发送到消息队列中。
下面是`msgsnd`的语法及用法:```c#include <mqueue.h>int msgsnd(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio);```参数说明:* `mqdes`:消息队列描述符,通过`mqueue_open` 函数获得。
* `msg_ptr`:指向要发送的消息的指针。
* `msg_len`:消息的长度。
* `msg_prio`:消息的优先级。
`msgsnd`函数用于将一个消息发送到指定的消息队列中。
如果消息队列已满,则根据系统的配置,可能会阻塞或返回错误。
以下是一个使用`msgsnd` 的简单示例:```c#include <stdio.h>#include <stdlib.h>#include <mqueue.h>#define QUEUE_NAME "/test_queue"#define MAX_MSG_SIZE 1024#define MAX_MSGS 10int main() {mqd_t mq;char buffer[MAX_MSG_SIZE];unsigned int prio = 1;size_t msg_len;// 打开或创建消息队列mq = mqueue_open(QUEUE_NAME, O_CREAT | O_WRONLY, 0666, NULL);if (mq == (mqd_t)-1) {perror("mqueue_open");exit(EXIT_FAILURE);}// 发送消息for (msg_len = 0; msg_len < MAX_MSG_SIZE; msg_len++) { sprintf(buffer + msg_len, "Message length: %zu", msg_len);}if (msgsnd(mq, buffer, msg_len, prio) == -1) {perror("msgsnd");exit(EXIT_FAILURE);}printf("Message sent successfully\n");// 关闭消息队列if (mqueue_close(mq) == -1) {perror("mqueue_close");exit(EXIT_FAILURE);}return 0;}```在此示例中,我们使用`mqueue_open` 打开或创建名为`/test_queue` 的消息队列,并获得其描述符。
linux postthreadmessage 参数Linux中的post_thread_message函数是一种线程间通信的方法,可以用来发送消息到目标线程的消息队列中。
本文将详细介绍post_thread_message函数的参数和使用方法。
post_thread_message函数是Linux下POSIX线程库提供的一个函数,它的原型如下:```cint post_thread_message(pthread_t thread, int msg_type, void *msg);```其中,参数解释如下:- `thread`:目标线程的线程ID,可以使用pthread_create函数创建线程时获取。
- `msg_type`:消息类型,可以是一个整数,用来区分不同的消息。
- `msg`:要发送的消息的内容,可以是任意类型的指针。
函数的返回值为0表示成功发送消息,否则返回一个错误码。
使用post_thread_message函数时,我们需要先创建目标线程并获得其线程ID。
下面是一个使用post_thread_message函数实现线程间通信的示例。
首先,我们需要在程序中定义一个全局变量来存储接收到的消息:```cvoid *received_msg;```然后,在目标线程的入口函数中,使用一个无限循环来接收消息,并根据消息类型进行相应的处理:```cvoid *thread_func(void *arg) {while(1) {int msg_type;void *msg;if(post_thread_message(pthread_self(), &msg_type, &msg) == 0) {switch(msg_type) {case MSG_TYPE_1:// 处理消息类型1break;case MSG_TYPE_2:// 处理消息类型2break;// 其他消息类型的处理}}}return NULL;}```在其他线程中,我们可以使用post_thread_message函数来向目标线程发送消息:```cint main() {// 创建目标线程,并获取线程ID保存在变量thread中pthread_t thread;pthread_create(&thread, NULL, thread_func, NULL);// 发送消息到目标线程int msg_type = MSG_TYPE_1;void *msg = "Hello, world!";post_thread_message(thread, msg_type, &msg);// 其他操作pthread_join(thread, NULL);return 0;}```在上面的示例中,我们首先创建了一个目标线程,并获取其线程ID保存在变量thread中。
POSIX标准理解POSIX标准总体分析? POSIX,全称为可移植性操作系统接口,是一种关于信息技术的IEEE标准。
它包括了系统应用程序接口(简称API),以及实时扩展[C语言]。
该标准的目的是定义了标准的基于UNIX操作系统的系统接口和环境来支持源代码级的可移植性。
现在,标准主要提供了依赖C语言的一系列标准服务,再将来的版本中,标准将致力于提供基于不同语言的规范。
该标准对核心需求部分定义了一系列任何编程语言都通用的服务,这一部分服务主要从其功能需求方面阐述,而非定义依赖于编程语言的接口。
语言规范主要有两部分组成。
一部分包括了访问核心服务的编程语言的标准接口,这些核心服务为标准中基于编程语言的核心需求部分所定义;另一部分包含了一个特殊语言服务的标准接口。
基于任何语言,与该标准一致的执行都必须遵循语言规范的任何章节。
该标准一共被分为四个部分:(1)陈述的范围和一系列标准参考(第一章);(2)定义和总概念;(第二章)(3)各种接口设备;(第三章到第九章,第十一章到第十五章)(4)数据交换格式;(第十章)该标准的主要目的有:(1)面向应用(2)定义接口,而不是它的具体实现;(3)涉及资源和可移植性,而非对象;(4)基于c语言;(5)无超级用户,无系统管理;(6)最小限度的接口,最小限度的定义;(7)应用领域广泛;(8)对以前的实现进行最小限度改变;(9)对原有程序代码做最小的修改;(10)实时扩展;以下就对各个章节做简要分析。
第一章概述1.1范围定义范围的关键要素有:(1)定义足够的一套功能适用于实时应用程序领域的重要部分;(2)定义足够的实现规范和性能相关的函数,以便允许实时应用程序完成系统的确定性的响应;1.2?一致性系统须支持标准中定义的接口,系统能够提供标准中没有要求到的函数和工具。
在遵循于该标准的实现中,一种一致性文档是需要用到的,它必须具有与该标准相同的结构,包含有全名,数字,和标准所指示的日期,以及头文件<limits.h>和<unistd.h>中的界限值等等。
posix 消息队列原理POSIX消息队列是一种进程间通信的机制,它允许不同的进程通过消息进行数据交换。
在本文中,我们将探讨POSIX消息队列的原理,包括它的工作原理、特点和使用方法。
POSIX消息队列是一种可靠的、异步的通信机制,它允许进程通过发送和接收消息来进行通信。
与其他进程间通信机制相比,如管道或共享内存,POSIX消息队列具有以下优势:1. 高效性:POSIX消息队列使用内核缓冲区来存储消息,因此在发送和接收消息时不需要数据复制。
这使得消息队列在处理大量数据或频繁通信时更加高效。
2. 可靠性:消息队列提供了可靠的消息传递机制。
发送方可以确认消息是否已成功发送,接收方可以确认消息的发送者和消息的优先级。
3. 异步性:发送方和接收方可以独立地进行操作,不需要彼此等待。
这使得进程可以以自己的速度进行工作,而不受其他进程的影响。
4. 有序性:消息队列可以按照发送的顺序进行消息传递,保证了消息的有序性。
POSIX消息队列的工作原理如下:1. 创建消息队列:进程通过调用`mq_open`函数来创建一个消息队列。
在创建消息队列时,需要指定一个唯一的名称和一些属性,如消息的最大长度和最大数量。
2. 发送消息:发送方通过调用`mq_send`函数来向消息队列发送消息。
发送方需要指定消息队列的名称、消息的内容和消息的长度。
如果消息队列已满,发送方可以选择等待或立即返回。
3. 接收消息:接收方通过调用`mq_receive`函数来从消息队列接收消息。
接收方需要指定消息队列的名称、缓冲区的地址和缓冲区的大小。
如果消息队列为空,接收方可以选择等待或立即返回。
4. 关闭消息队列:进程通过调用`mq_close`函数来关闭消息队列。
关闭消息队列会释放相关的资源。
使用POSIX消息队列的步骤如下:1. 创建消息队列:调用`mq_open`函数来创建一个消息队列,指定消息队列的名称和属性。
2. 发送消息:调用`mq_send`函数来向消息队列发送消息,指定消息队列的名称、消息的内容和长度。
请教关于posix消息队列无法设置阻塞超时的问题请教老鸟:小菜在一个线程中创建一个posix消息队列,用mq_timedreceive来阻塞接收,发现在消息队列空的时候,并没有等待超时时间到达,而是立即返回。
不知道小菜在哪里出了问题,还望老鸟给于指教。
RHEL AS5.1内核版本2.6.18代码如下:消息队列创建:struct mq_attr newattr;mq_unlink("/m请问这个用到了什么知识qLcd");newattr.mq_maxmsg = 10;newattr.mq_curmsgs =0;newattr.mq_msgsize = sizeof(STRU_LCDMSG);if(ERROR == (msgQIdLcd = mq_open("/mqLcd", O_RDWR|O_CREAT, 0x777, &newattr))){PDBG_L0("LCD消息队列创建错误!\n");perror("<errno>");return;}接收消息队列如下:struct timespec tmout;_sec = 6;if(ERROR != (rcvlen = mq_timedreceive(msgQIdLcd, (char*)&struLcdMsgTmp, sizeof(STRU_LCDMSG), (unsigned *)NULL, (const struct timespec *)&tmout))) //if(ERROR != (rcvlen = mq_receive(msgQIdLcd, (char*)&struLcdMsgTmp, sizeof(STRU_LCDMSG), (unsigned *)NULL))){printf("receive a data, len = %d\n", rcvlen);}else{printf("rcv timeout\n");perror("<error>");printf("errno = %d\n", errno);}小菜偶发现用mq_receive可以正常阻塞,但用mq_timedreceive或mq_timedsend 就会立即返回,用gcc或arm-linux-gcc编译后都如此,请问我的问题可能出在哪里?希望大大们能够不吝指教,这个问题困惑小弟有段时间了,多谢了没有人用过么:em16:快两年了,也没有人回复,还是自己回复吧,以防有跟偶一样遇到这个问题的小菜搜到这篇帖子。
POSIX消息队列是linux进程间通信的重要方式,下面按照创建,使用,关闭的顺序讲述了POSIX消息队列的使用方法:创建POSIX消息队列:mq_open#include<mqueue.h>mqd_t mq_open(const char *name,int oflag,int mode,mq_addr *attr);参数说明:Name:消息队列的名字字符串,必须以’/’开头,否则会出错。
Oflag: 表示打开的方式,1.首先必须说明读写方式,可以使以下的值之一:O_RDONLY:建立的队列是只读的O_WRONLY:建立的队列是只写的O_RDWR:建立的队列是可读可写2.必须有O_CREATE,说明是创建消息队列。
3.还有可选的选项:O_NONBLOCK:说明在创建的队列上发送和接收消息时,如果没有资源,不会等待,之间返回,如果不设置这个选项,缺省是会等待。
O_EXCL:在创建队列时,检测要创建的队列的名字是否已经存在了,如果已存在,函数会返回出错可以以或的方式形成Oflag,例如:O_RDWR|O_CREAT|O_EXCL Mode:是一个可选参数,在oflag中含有O_CREA T标志且消息队列不存在时,才需要提供该参数。
表示默认的访问权限,这个权限和文件访问的权限是相同的,取值也相同。
Mode可以由多个值组合而成,如:S_IRUSR|S_IWUSR,队列的所有者有读和写的权限。
Attr:指向结构struct mq_attr的指针。
我们可以在创建队列时通过这个结构设置队列的最大消息数和每个消息的最大长度。
struct mq_attr{long mq_flags; // 0或者O_NONBLOCK,说明是否等待long mq_maxmsg; //队列中包含的消息数的最大限制数long mq_msgsize; //每个消息大小的最大限制数long mq_curmsgs; //当前队列中的消息数}mq_maxmsg和mq_msgsize属性只能在创建消息队列时通过mq_open来设置。
mq_open 只会设置该两个属性,忽略另外两个属性。
mq_curmsgs属性只能被获取而不能被设置。
当attr参数为NULL时则使用linux的默认值msg_max ,msgsize_max 。
而使用mq_open创建一个新的队列时,attr只能给它指定mq_maxmsg,mq_msgsize这两个属性。
mq_open忽略attr结构中的另外两个成员。
在创建过程中需要注意的是,指定的这两个属性都必须小于等于msg_max或者msgsize_max的。
查看系统中消息队列的这两个限制值的方法是:cat /proc/sys/fs/mqueue/msg_maxcat /proc/sys/fs/mqueue/msgsize_max系统默认值有些时候不够大,需要我们对这个限制数进行修改,方法如下:修改/etc/sysctl.conf 在这个文件中添加#mqueue max fs.mqueue.msg_max=100 fs.mqueue.msgsize_max=9000 fs.mqueue.queues_max=520 保存好后重启系统就好了。
返回值:函数的返回值是mqd_t类型,是消息队列的描述符。
这实际是一个整数。
当函数执行出错时,会返回-1.要注意的是,描述符对于不同的进程/线程是不一样的,因此不同的进程/线程不能使用其他进程/线程的描述符。
打开消息队列:当一个进程在使用消息队列发送和接收消息之前,必须先打开消息队列。
以获得专属于本进程的对于这个消息队列的描述符。
打开消息队列的函数和创建消息队列的函数是一样的,区别在于参数要少2个。
mqd_t mq_open(const char *name,int oflag,);参数:Name:消息队列的名字字符串,必须以’/’开头,否则会出错。
Oflag: 表示打开的方式,说明读写方式,可以使以下的值之一:O_RDONLY:建立的队列是只读的O_WRONLY:建立的队列是只写的O_RDWR:建立的队列是可读可写返回值:函数的返回值是mqd_t类型,是消息队列的描述符。
在发送和接收消息队列的函数中需要这个描述符来指定是哪个消息队列。
这个值实际是一个整数。
当函数执行出错时,会返回-1.要注意的是,描述符对于不同的进程/线程是不一样的,因此不同的进程/线程不能使用其他进程/线程的描述符。
获取消息队列的属性一个进程在发送和接收消息之前,需要了解消息对象的属性,如消息的最大长度。
以便设定接收和发送的buffer大小。
mqd_t mq_getattr(mqd_t mqdes, struct mq_attr *attr);参数:Mqdes:打开消息队列时获取的描述符。
Attr:指向结构struct mq_attr的指针,用来获取消息队列的四个属性struct mq_attr{long mq_flags; // 0或者O_NONBLOCKlong mq_maxmsg; //队列中包含的消息数的最大限制数long mq_msgsize; //每个消息大小的最大限制数long mq_curmsgs; //当前队列中的消息数}设置消息队列属性我们可以设置消息队列的属性,实际只能设置flag标志,说明队列中没有消息时,接收消息的进程是否在队列上继续等待。
mqd_t mq_setattr(mqd_t mqdes, struct mq_attr *newattr, struct mq_attr *oldattr);参数:Mqdes:打开消息队列时获取的描述符。
Attr:指向结构struct mq_attr的指针,用来获取消息队列的最大消息个数和最大消息长度。
放到数据结构的mq_maxmsg和mq_msgsize中。
struct mq_attr{long mq_flags; // 0或者O_NONBLOCK,只能设置这个long mq_maxmsg; //队列中包含的消息数的最大限制数long mq_msgsize; //每个消息大小的最大限制数long mq_curmsgs; //当前队列中的消息数}oldattr:用来保存设置之前的attr值,可以为NULL.发送消息进程在打开消息队列后,可以使用下面的函数发送消息#include <mqueue.h>int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio);参数:mqdes: 打开消息队列时获得的描述符。
ptr: 指向发送缓冲区的指针,发送缓冲区存放了要发送的数据。
Len: 要发送的数据的长度。
prio :消息的优先级;它是一个小于MQ_PRIO_MAX的数,数值越大,优先级越高。
POSIX消息队列在调用mq_receive时总是返回队列中最高优先级的最早消息。
如果消息不需要设定优先级,那么可以在mq_send是置prio为0,mq_receive的prio置为NULL。
返回值:发送成功,返回0,失败,返回-1.接收消息进程在打开消息队列后,可以使用下面的函数接收消息。
ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *prio);参数:mqdes: 打开消息队列时获得的描述符。
ptr: 指向接收缓冲区的指针。
接收缓冲区用来存放收到的消息。
Len: 接收缓冲区的长度。
len不能小于mq_msgsize,否则会返回EMSGSIZEprio :消息的优先级;它是一个小于MQ_PRIO_MAX的数,数值越大,优先级越高。
POSIX消息队列在调用mq_receive时总是返回队列中最高优先级的最早消息。
如果消息不需要设定优先级,那么可以在mq_send是置prio为0,mq_receive的prio 置为NULL。
返回值:接收成功,返回0,失败,返回-1.消息队列的关闭mqd_t mq_close(mqd_t mqdes);关闭消息队列,但不能删除它成功返回0,失败返回-1删除消息队列mqd_t mq_unlink(const char *name);成功返回0,失败返回-1当某个进程还没有关闭此消息队列时,调用mq_unlink时,不会马上删除队列,当最后一个进程关闭队列时,该队列被删除例子:下面的例子给出了发送和接收进程中如何创建消息队列,获取消息队列属性,发送消息和接收消息发送进程:创建并发送消息。
#include <mqueue.h>#include <fcntl.h>#include <sys/stat.h>#include <stdio.h>#include <stdlib.h> int main(int argc, char **argv){int flags = 0;mqd_t mqd;flags = O_RDWR | O_CREAT;char *mq_name = (char*)"/MQ_Msg";struct mq_attr attr;long int msgsize = 1024;long int maxmsg = 200;attr.mq_msgsize = msgsize;attr.mq_maxmsg = maxmsg;mqd = mq_open(mq_name, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, &attr);if (mqd == -1){printf("mq create error\n");return 0;}printf("Create MQ success!\nMax msgs = %ld, Max bytes/msg = %ld\n", attr.mq_maxmsg, attr.mq_msgsize);char msg[1024] = "hello";unsigned int prio = 1;int i;for (i = 0; i < 100; i++){mq_send(mqd, msg, msgsize, prio);}mq_close(mqd);return 0;}接收进程:打开并接收消息#include <unistd.h>#include <fcntl.h>#include <sys/stat.h>#include <stdio.h>#include <stdlib.h> int main(int argc, char **argv){mqd_t mqd;long n;int flags = 0;unsigned int prio = 0;char *buff;struct mq_attr attr;char *mq_name = (char*)"/MQ_Msg";flags = O_RDONLY;mqd = mq_open(mq_name, flags);if (mqd == -1){printf("mq open error\n");return 0;}mq_getattr(mqd, &attr);buff = (char*)malloc(attr.mq_msgsize);while ((n = mq_receive(mqd, buff, attr.mq_msgsize, &prio))){printf("read %ld bytes, msg is %s, priority = %u\n", n, buff, prio);}mq_close(mqd);return 0;}进阶话题:异步事件通知POSIX消息队列可以在空队列收到第一个消息时发送事件通知给需要的进程。