SystemV消息队列
<!--[if !supportLists]-->1、
<!--[endif]-->函数列表
<!--[if !supportLists]-->Ø
<!--[endif]-->key_t ftok(const char *pathname,
int proj_id);
//# include <sys/types.h>
//# include <sys/ipc.h>
IPC消息队列有一个key的属性(类型为key_t),一般由此函数产生,产生方法为:根据文件名pathname(必须存在且有权限访问)得到索引节点号,然后将索引节点号和子序列号(proj_id)组成ID标示。
<!--[if !supportLists]-->Ø
<!--[endif]-->int msgget(key_t key, int msgflg);
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
此函数有两个作用:创建key属性为key的消息队列和返回key指定消息的msgid,其中msgid是消息队列的标示。
其中msgflg标示符可以指定创建消息队列的访问权限(一般为S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH用户读写,组和其它读);同时可以指定msgget函数执行的操作,在创建消息队列时,msgflg必须有IPC_CREAT。
如果msgflg为0,则只返回消息队列的msgid。
此函数成功时,返回非负消息队列标示;失败时返回-1。
<!--[if !supportLists]-->Ø
<!--[endif]-->int msgsnd(int msqid, const void
*msgp, size_t msgsz, int msgflg);
#include <sys/msg.h>
其中msgid是msgget返回的消息队列标识符,msgp是一个结构体指针,msgsz是结构体中具体数据的长度,msgflg可以为0或者IPC_NOWAIT。
当msgflag指定IPC_NOWAIT时,msgsnd函数成为非阻塞,当由于一些限制条件(例如没有存放消息的可用空间时)出现时,该函数立即放回。
发送成功返回0,发送失败返回-1.
<!--[if !supportLists]-->Ø
<!--[endif]-->ssize_t msgrcv(int msqid, void
*msgp, size_t msgsz, long msgtyp, int msgflg);
msgsz是结构体(msgp)中保存数据的最大值,也是函数能够返回的最大数据量。而具体的接收的数据量,由函数返回值确定。msgflag可以为0或者IPC_NOWAIT。msgtyp指定待接收消息的类型。
当msgflag指定为IPC_NOWAIT时,msgrcv函数成为非阻塞,当由于一些限制条件(例如消息队列中没有消息)时,该函数立即返回。
其中type的规则为:
当type=0时,返回消息队列中的第一个消息;
当type>0时,返回类型值为type的消息;
当type<0时,返回类型值小于或者等于type绝对值的消息中类型值最小的消息。
msgrcv函数成功时返回接收消息的数据量,失败返回-1.
<!--[if !supportLists]-->Ø
<!--[endif]-->int msgctl(int msqid, int cmd,
struct msqid_ds *buf);
消息队列控制函数。Msgid为消息队列标示,cmd为具体的命令(一共有三种),buf用来设置或取得消息队列的msgid_ds结构体。
IPC_RMID:删除msgid指定的消息队列。Buf参数忽略,为0
IPC_SET:设置消息队列msgid_ds结构体的四个成员:msg_perm.uid,msg_perm_gid,msg_perm.mode和msg_qbytes。它们的值来自由buf指向的结构体中的相应成员。
IPC_STAT:给调用者返回消息队列msgid_ds结构体,通过buf返回。
<!--[if !supportLists]-->2、
<!--[endif]-->实例解析
<!--[if !supportLists]-->Ø
<!--[endif]-->create|send|receive|remove
消息队列的创建和删除、消息的发送和接收。采用默认的struct
msgbuf作为消息体。
// mymsgcreate.c
#include <sys/msg.h>
#include
<fcntl.h> // O_CREATE
#include
<sys/types.h> // pid_t
#include <sys/stat.h>
int main(int
argc, char **argv)
{
int c,
oflag, mqid;
oflag = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH
| IPC_CREAT;
//设置权限(用户读写,组和其它读)
//指定msgget具体操作(创建消息队列并返回ID)
if((mqid
= msgget(ftok("test3", 0), oflag))<0)
printf("create error!/n");
//ftok的pathname参数所指向的文件必须存在
printf("mqid===%d/n",mqid);
exit(0);
}
//#gcc mymsgcreate.c
–o mycreate
|
创建一个消息队列必须满足的条件是:ftok函数的pathname指向的文件已经存在;msgflg中有IPC_CREATE标示。权限要设置正确,用户要有读和写权限。
// mymsgsnd.c
#include <sys/msg.h>
#include
<fcntl.h> // O_CREATE
#include
<sys/types.h> // pid_t
#include <sys/stat.h>
int
main(int argc,
char **argv)
{
struct msgbuf *ptr;
int mqid;
if((mqid
= msgget(ftok("test3", 0), S_IWUSR))<0)
printf("create
error!/n");
//
S_IWUSR权限可以省略,消息队列的权限已经设置了,这里可以为0
//msgget函数的作用是返回消息队列的ID
ptr = calloc(sizeof(long)+7,
sizeof(char));
ptr->mtype = 100;
strcpy(ptr->mtext,"abcdefg");
msgsnd(mqid, ptr,7, 0);
exit(0);
}
// gcc -D_GNU_SOURCE mymsgsnd.c -o mysend
|
消息队列已经创建了,此时msgget函数只是起获得消息队列标示的作用,因此msgflg可以为0。
关于编译选项-D_GNU_SOURCE说明如下:
/usr/include/src/msg.h文件中
#ifdef __USE_GNU
/* Template for struct to be used as argument for `msgsnd' and `msgrcv'. */
struct msgbuf
{
long int mtype; /* type of received/sent message */
char mtext[1]; /* text of the message */
};
#endif
#ifdef _GNU_SOURCE
# define __USE_GNU 1
#endif
|
因此要想使用struct
msgbuf,必须#define _GNU_SOURCE,也可以通过编译选项加进去。
注意msgbuf成员mtext是大小为1的字符数组,而经测试:消息数据的长度不受此限制。例如上面的例子即发送了7个字符。这可能是与结构体成员内存存储有关,也就是可能已经超出结构体的存储范围,这对普通的数据类型是不允许,但对结构体变量是可以的,正如
strcpy(ptr->mtext,"abcdefg");操作是合法的。
//mymsgrec.c
#include <sys/msg.h>
#include
<fcntl.h> // O_CREATE
#include
<sys/types.h> // pid_t
#include <sys/stat.h>
#define MAXMSG (8192
+ sizeof(long))
int
main(int argc,
char **argv)
{
int mqid,n;
struct msgbuf *buff;
if((mqid
= msgget(ftok("test3", 0), S_IRUSR))<0)
printf("create
error!/n");
//S_IWUSR权限可以省略,消息队列的权限已经设置了,这里可以为0
//msgget函数的作用是返回消息队列的ID
buff = malloc(MAXMSG);
n =msgrcv(mqid, buff, MAXMSG, 100,
0);
printf("read %d bytes, type =
%ld,mtext=%s/n", n, buff->mtype,buff->mtext);
exit(0);
}
// gcc -D_GNU_SOURCE mymsgrec.c -o myrec
|
通消息发送,此时消息队列已经创建,msgget函数只起获得消息队列标示的作用,msgflg可以为0.
//mymsgrmid.c
#include <sys/msg.h>
#include
<fcntl.h> // O_CREATE
#include
<sys/types.h> // pid_t
#include <sys/stat.h>
int
main(int argc,
char **argv)
{
int mqid;
mqid = msgget(ftok("test3",
0), 0);
msgctl(mqid, IPC_RMID, 0);
exit(0);
}
//gcc mymsgrmid.c –o myrm
|
struct msqid_ds *buf参数被忽略,为0。
<!--[if !supportLists]-->Ø
<!--[endif]-->mystruct
自定义消息结构体进行消息的发送和接收。
msgsnd和msgrcv函数的void* msgp是具有struct msgbuf模板的结构体变量。
首先分析下struct msgbuf的结构。
struct msgbuf
{
long int mtype; /* type of received/sent message */
char mtext[1]; /* text of the message */
}; <!--[if !supportLineBreakNewLine]--> <!--[endif]-->
|
有两个成员,一个为long int保存着消息类型,一个为char数组,保存着具体的消息数据。
因此,以此结构体作为模板的结构体至少有两个成员,一个为long int,一个为char数组。如果结构体的成员变量不只这两个,必须保证保存消息类型的long int和保存消息数据的char数组,连续存储,并位于结构体末尾。
现在自定义一个以struct msgbuf为模板的结构体。
struct mymesg {
long mesg_len; /* #bytes in mesg_data, can be 0 */
long mesg_type; /* message type, must be > 0 */
char mesg_data[MAXMESGDATA];
};
|
int msgsnd(int msqid, const void *msgp,
size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t
msgsz, long msgtyp, int msgflg);
两个函数中msgp结构体指针为部分mymesg结构体指针,指向mseg_type。也就是消息接收和发送函数的void* msgp参数为&(ptr->mesg_type)。也就是消息传输的结构体不包含mesg_len成员数据,在接收端,mesg_len通过msgrcv函数的返回值确定。
从实现方式和结果来看,使用struct
msgbuf和自定义结构体没有差异。
//mymesg.h
#include <sys/msg.h>
#include
<fcntl.h> // O_CREATE
#include <sys/types.h>
// pid_t
#include <sys/stat.h>
#include
<limits.h>
#define MAXMESGDATA (PIPE_BUF - 2*sizeof(long))
#define MESGHDRSIZE (sizeof(struct mymesg) - MAXMESGDATA)
struct mymesg {
long mesg_len; /* #bytes in mesg_data, can be 0 */
long mesg_type; /* message type, must be > 0 */
char mesg_data[MAXMESGDATA];
};
|
//mystructsnd.c
#include
"mymesg.h"
int main(int
argc, char **argv)
{
struct mymesg *ptr;
int mqid;
if((mqid =
msgget(ftok("test3", 0), S_IWUSR))<0)
printf("create error!/n");
ptr = calloc(2*sizeof(long)+7,
sizeof(char));
ptr->mesg_type = 100;
ptr->mesg_len = 7;
strcpy(ptr->mesg_data,"abcdefg");
msgsnd(mqid,
&(ptr->mesg_type),ptr->mesg_len, 0);
exit(0);
}
// gcc -D_GNU_SOURCE mystructsnd.c -o mystructsend
|
// mystructrec.c
#include
"mymesg.h"
#define MAXMSG (8192
+ sizeof(long))
int
main(int argc,
char **argv)
{
int mqid,n;
struct mymesg *buff;
if((mqid =
msgget(ftok("test3", 0), S_IRUSR))<0)
printf("create
error!/n");
buff = malloc(MAXMSG);
buff->mesg_type=100;
n
=msgrcv(mqid,&(buff->mesg_type), MAXMSG,buff->mesg_type, 0);
buff->mesg_len=n;
printf("read %d bytes, type =
%ld,mtext=%s/n", buff->mesg_len,
buff->mesg_type,buff->mesg_data);
exit(0);
}
// gcc -D_GNU_SOURCE mystructrec.c -o mystructrec
|
<!--[if !supportLists]-->3、
<!--[endif]-->小结
<!--[if !supportLists]-->Ø
<!--[endif]-->消息队列和管道(pipe和FIFO)的区别:
管道可以比作为“传输带”,货物(数据流)是按照放上去的顺序达到的;
消息队列可以比作为“仓库”,货物是静态地存储的。
管道对于存货和取货的双方有一定的要求:没有存货方,就不能有取货方(管道只能先以写方式打开后,才能以读方式打开);没有货,就不能取货(对管道写数据后,才能读数据);并且对货物形式有要求(存货和取货双方必须定义一致的数据协议)。
消息队列的取货和存货方不存在彼此阻塞约束的现象,双方都是独立自由的,消息队列只是一个公共的存货的仓库;双方也不需要关心数据协议,消息队列已经将数据以消息形式保存在队列中。
<!--[if !supportLists]-->Ø
<!--[endif]-->Posix消息队列和SystemV消息队列区别
新的应用程序应考虑使用Posix消息队列,不过大量的现有代码使用SystemV消息队列。
Posix消息队列遗漏的主要特性是从队列中读取指定优先级消息的能力;这两种消息都不适用真正的描述字,因此从而造成在消息队列上使用select或poll的困难。
<!--[if !supportLists]-->Ø
<!--[endif]-->ipcs命令
此命令用于显示系统中进程间通信的内核对象。
#ipcs –qa
显示所有的进程间通信对象
#ipcs –q
显示消息队列对象
<!--[if !supportLists]-->Ø
<!--[endif]-->消息复用是指在一个消息队列上存储多个种类的消息,这些消息通过struct msgbuf的mtype来区分。
<!--[if !supportLists]-->Ø
<!--[endif]-->消息队列存在一定的限制,包括:每个消息的最大字节数;任何一个消息队列上的最大字节数;系统范围的最大消息队列数;系统范围的最大消息数。
分享到:
相关推荐
ftok:将路径名和项目标识符转换为System V IPC密钥 msgget:获取消息队列标识符 msgsnd:将消息发送到队列 msgrcv:从队列接收消息 msgctl:消息控制操作 有关系统调用的更多信息,请访问您的手册页。 这个想法是...
7. **消息队列在Unix环境下的应用**:在Unix环境中,消息队列通常是基于POSIX标准的,如System V IPC或Berkeley套接字。这些系统提供了一套API来创建、发送和接收消息,开发者可以利用这些API在C、C++等语言中实现...
System V IPC(Interprocess Communication)是Unix/Linux系统中实现进程间通信的一种方式,它提供了三种主要机制:信号量(Semaphore)、消息队列(Message Queue)和共享内存(Shared Memory)。在这个问题中,...
- **System V IPC** 包括:System V消息队列、System V信号灯、System V共享内存区。 - **Posix IPC** 包括:Posix消息队列、Posix信号灯、Posix共享内存区。 #### 三、IPC机制详解 ##### 1. 管道(Pipe)及有名...
2. 消息队列(Message Queue) 消息队列是一种简单但有效的进程间通信方式,允许进程发送和接收特定格式的消息。它提供了有序的消息传递,并且可以选择性地接收消息。使用`msgget`、`msgsnd`、`msgrcv`和`msgctl`...
### System V IPC与POSIX IPC通信机制详解 #### 一、概述 在计算机科学领域,进程间通信(Inter-Process Communication, IPC)是操作系统提供的核心功能之一,它允许不同的进程之间进行数据交换和同步操作。System...
在 System V IPC 机制中,包括消息队列(message queue)、信号量(semaphore)和共享内存(shared memory)等机制。 System V IPC 机制的实现是通过系统调用来访问 ipc 对象的。进程如果要访问 ipc 对象,需要通过...
system v ipc 3.1 introduction 27 3.2 key_t keys and ftok function 28 3.3 ipc_perm structure 30 3.4 creating and opening ipc channels 30 3.5 ipc permissions 32 3.6 identifier reuse 34 3.7 ipcs ...
在SYSV(System V)操作系统中,提供了多种IPC方式,其中包括信号量(Semaphore)、消息队列(Message Queue)和共享内存(Shared Memory)。本教程将主要讨论SYSV IPC中的信号量。 信号量是一种特殊的同步机制,它...
进程间通信机制包括共享内存(shared memory)、信号量(semaphores)和消息队列(Message Queue)等一系列进程通信方式。System V IPC 的进程间通信机制一个显著特点是:在内核中它的具体实例是以对象的形式出现的...
Linux系统中,进程间通信的方式主要包括:socket、named pipe、message queue、signal、shared memory等。而在Java系统中,主要依赖socket和named pipe等方式进行进程间的通信。然而,对于Android操作系统而言,其...
http://www.ibm.com/developerworks/cn/linux/l-ipc/part4/ PHP的sysvmsg模块是对Linux系统支持的System V IPC中的System V消息队列函数族的封装。我们需要利用sysvmsg模块提供的函数来进进程间通信。先来看一段...
标题中的“进程间通信2,msgq4.c msg_send.c msgl.c msgq1.c”表明这个主题聚焦在操作系统中的进程间通信(IPC, Inter-Process Communication)技术,特别是使用消息队列(Message Queue)这一机制。消息队列是进程...
2. **System V IPC**:引入了更为复杂且功能强大的机制,如消息队列、信号量和共享内存。 3. **POSIX IPC**:为了标准化IPC接口,POSIX定义了一系列标准,包括线程、消息队列和信号量等。 4. **基于Socket的IPC**:...
在Linux系统中,消息队列的实现基于System V IPC(Inter-Process Communication)机制。消息队列可以看作是一个存储在内核空间的队列,由多个消息构成,每个消息有一个类型和数据内容。进程可以通过发送或接收消息来...
消息队列(Message Queue)是另一种IPC机制,它允许不同进程间以消息的形式发送和接收数据。消息队列与管道相比,可以实现双向通信,并且消息可以是任意长度的数据。消息队列有自己的限制,例如大小限制以及创建队列...
5. **进程间通信(IPC)**:掌握管道(pipe)、信号量(semaphore)、共享内存(shared memory)和消息队列(message queue)等IPC机制。 6. **Socket网络编程**:学习TCP/IP协议,编写网络客户端和服务器程序,实现...