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 平台的吞吐量更好。
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消息队列可以在空队列收到第一个消息时发送事件通知给需要的进程。