Linux进程IPC浅析[进程间通信SystemV消息队列]
- System V IPC的概述
- System V IPC对象访问
- System V IPC消息队列
System V IPC的概述
System V Ipc概述:
1:Unix系统存在信号,管道和命名管道等基本通信机制
2:System V引入三种高级进程间通信机制
消息队列,共享内存和信号量
IPC对象存在于内核中而不是文件系统中,由用户控制释放,不像管道的释放由内核控制
3:IPC对象用过其标识符来引用和访问,所有IPC对象在内核空间中有唯一性表示ID,在用户空间中的唯一标识为key
Linux IPC继承来自System V Ipc
System V IPC对象访问
IPC对象是全部对象
可用ipcs,ipcrm等命令查看或删除
从上面我们可以看到共享内存端.信号量数组和消息队列
每个IPC对象的都由get函数创建
msgget,shmget,semget调用get函数时必须制定关键字key
IPC对象的权限和所有者结构体:
struct ipc_perm{
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
mode_t mode;//权限
......;
}
System V IPC消息队列
消息队列概述:
1:消息队列是内核中的一个链表
2:用户进程将数据传输到内核后,内核重新添加一些如用户ID,组ID,读写进程的ID和优先级等相关信息后并打成一个数据包成为消息
3:允许一个或者多个进程往消息队列中写消息和读消息,但一个消息只能被一个进程读取,读取完毕后就自动删除
4:消息队列具有一定的FIFO特性,消息可以按照顺序发送到队列中,也可以几种不同的方式从队列中读取,每个消息队列在内核中用一个唯一的IPC标识ID表示
5:消息队列的实现包括创建和打开消息队列,发送消息,读取消息,和控制消息队列四种操作
消息队列属性:
消息队列的属性:
struct msgid_ds{
struct ipc_perm msg_perm;//IPC对象的权限和所有者结构体
msgqnum_t msg_qnum; //队列中的消息个数
msglen_t msg_qbytes; //队列中最大的字节数
pid_t msg_lspid; //最后一个消息发送者的pid
pid_t msg_lrpid; //最后一个消息接受者的pid
time_t msg_stime; //最后发送的时间
time_t msg_ctime; //消息队列最后改变的时间
......
}
消息队列函数:
打开或者创建消息队列
#include<sys/msg.h>
int msgget(key_t key,int flag);
返回:成功返回内核中消息队列的表示ID,出错返回-1(不存在则创建,存在则打开)
参数:
key:用户指定的消息队列健值
flag:IPC_CREAT,IPC_EXCL等权限组合(IPC_CREATE | IPC_EXCL |0777)
注意:若创建消息队列,key可制定健值,也可将之设置为
IPC_PRIVATE.若打开进行查询,则key不能为0必须是一个非0的值否则查询不到;
消息队列的控制函数:
#include<sys/msg.h>
int msgctl(int msgid,int cmd,struct msqid_ds *buf);
返回:成功返回0,出错返回-1
参数:
msgid:消息队列ID
buf:消息队列属性指针
cmd(有很多):
IPC_STAT获取消息队列的属性,取此队列的msqid_ds结构,并将其存放在buf指向的结构中去
IPC_SET:设置属性,按有buf指向的结构中的值,设置与此队列相关的结构中的字段
IPC_RMID:删除队列,从系统中删除该消息队列以及仍在该队列上的所有数据
消息队列的发送函数:
消息队列的发送:
#include<sys/msg.h>
int msgsnd(int msgqid,const void *ptr,size_t nbytes,int flag);
返回:成功返回0,出错返回-1
-------------
参数ptr:
struct mymesg{
long mtype; //消息类型
char mtext[512] //消息数据的本身
}
mtype指的是消息的类型,它由一个证书来代表,并且它只能是大于0的整数
mtext是消息数据的本身(文本或者二进制类型都可以)
在Linux中,消息的最大长度是4056个字节,其中包括mtype,它占有4个字节
结构体mymesg用户可自定义,但是第一个成员必须是mtype
-------------
参数nbytes:
指定消息的大小,不包括mtype的大小,也就是仅仅只是消息本身的大小(sizeof(struct mymesg) - sizeof(long))
参数flag:
0:阻塞
IPC_NOWAIT:类似与文件I/O的非阻塞状态
若消息队列已经满了(或者是队列中的消息总数等于系统限制值,或队列中的字节总数等于系统限制值):
指定IPC_NOWAIT
使得msgsnd立即出错返回EAGAIN,
如果指定0,则进程
阻塞直到有空间可以容纳要发送的消息
或从系统中删除了此队列
或捕捉到一个信号,并且从信号处理程序返回
消息队列的接受
#include<sys/msg.h>
ssize_t msgrcv(int msgqid,void *ptr,size_t nbytes,long type,int flag);
返回:成功返回消息的数据部分长度,出错返回-1
参数:
msgqid:消息队列ID
ptr:指向存放消息的缓存
nbytes:消息缓存的大小,不包括mtype的大小,计算方式:nbytes = sizeof(struct mymesg) - sizeof(long)如果大小不对,那么可能不能获取完整的消息;
type:消息类型
type==0 :获得消息队列中的第一个消息
type>0:获得消息队列中类型为type的第一个消息
type<0:获得消息队列中小于或等于type绝对值的消息
flag:0或者IPC_NOWAIT
直接上代码,msg_send
/*
* ===========================================================================
*
* Filename: msg_send.c
* Description: 消息的发送
* Version: 1.0
* Created: 2017年04月10日 21时54分13秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include<stdio.h>
#include<stdlib.h>
#include<sys/msg.h>
#include<string.h>
#define BUFFER 1024
typedef struct{
long type;
char content[BUFFER];
}MSG;
int main(int argc,char * argv[]){
if(argc < 2){
printf("缺少参数");
exit(EXIT_FAILURE);
}
//传入的字符串转换为整形
key_t key = atoi(argv[1]);
printf("key:%d\n",key);
int msg_id;
//第一次是创建,第二次是获取
if((msg_id = msgget(key,IPC_CREAT|IPC_EXCL|0777)) < 0){
printf("msg error\n");
}
MSG msg1 = {1,"hello"};
MSG msg2 = {2,"world"};
MSG msg3 = {5,"nihao"};
MSG msg4 = {7,"woshizzf"};
if(msgsnd(msg_id,&msg1,sizeof(MSG)-sizeof(long),IPC_NOWAIT) != 0){
printf("send msg1 error\n");
}
if(msgsnd(msg_id,&msg2,sizeof(MSG)-sizeof(long),IPC_NOWAIT) != 0){
printf("send msg2 error\n");
}
if(msgsnd(msg_id,&msg3,sizeof(MSG)-sizeof(long),IPC_NOWAIT) != 0){
printf("send msg3 error\n");
}
if(msgsnd(msg_id,&msg4,sizeof(MSG)-sizeof(long),IPC_NOWAIT) != 0){
printf("send msg4 error\n");
}
struct msqid_ds ds;
if(msgctl(msg_id,IPC_STAT,&ds) != 0){
perror("msgctl error");
}
printf("msg total:%ld\n",ds.msg_qnum);
printf("msg id:%d\n",msg_id);
return 0;
}
msg_get.c
/*
* ===========================================================================
*
* Filename: msg_get.c
* Description:
* Version: 1.0
* Created: 2017年04月10日 22时33分28秒
* Revision: none
* Compiler: gcc
* Author: (),
* Company:
*
* ===========================================================================
*/
#include<stdio.h>
#include<stdlib.h>
#include<sys/msg.h>
#include<string.h>
#define BUFFER 1024
typedef struct{
long type;
char content[BUFFER];
}MSG;
int main(int argc ,char * argv[]){
if(argc < 3){
printf("参数错误");
exit(EXIT_FAILURE);
}
key_t key = atoi(argv[1]);
long type = atoi(argv[2]);
printf("key:%d,type:%ld\n",key,type);
int msg_id;
if((msg_id = msgget(key,0777)) < 0){
perror("get msg error");
}
printf("msg_id:%d\n",msg_id);
MSG m;
if(msgrcv(msg_id,&m,sizeof(MSG)-sizeof(long),type,IPC_NOWAIT) < 0){
perror("get msg error\n");
}else{
printf("msg get type:%ld,content:%s\n",m.type,m.content);
}
return 0;
}
以上就是很简单的关于消息队列的调试代码.很简单.欢迎补充