System V
随内核持续的IPC 对象数据结构
struct ipc_perm{
key_t key;
uid_t uid;
gid_t gid;
uid_t cuid;
gid_t cgid;
unsigned short mode;
unsigned short seq;
}
消息队列提供了一个从一个进程向另一个进程发送一块数据的方法,每个数据块都被认为是一个类型,接收者进程接受的数据块可以有
不同的类型值。
消息队列也有管道一样的不足,就是每个消息队列的最大长度是有上限的,每个消息队列的总的字节数是有上限的,系统上可以创建的
消息队列总数也有限制。
创建消息队列或者访问一个消息队列,成功返回一个非负整数,即消息队列的标识码;失败返回-1
int msgget(key_t key,it oflag)
shell中: ipcs命令查看 已存在的消息队列 ipcrm -q msgid 删除一个消息队列
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<sys/un.h>
#include<fcntl.h>
#include<sys/msg.h>
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
}while(0)
int main(void)
{
int msgid;
//与open函数类似
msgid=msgget(1234,0666|IPC_CREAT);
//msgid=msgget(1234,0666|IPC_CREAT|IPC_EXCL);
//msgid=msgget(IPC_PRIVATE,0666|IPC_CREAT|IPC_EXCL);会创建一个新的消息队列,不能共享,只能用于本进程或者有亲缘关系进程之间通信
//不指定选项也能成功
//msgid=msgget(IPC_PRIVATE,0666);
//msgid=msgget(1234,0400|IPC_CREAT);
//msgid=msgget(1234,0600|IPC_CREAT);//无法打开
if(msgid==-1)
ERR_EXIT("msgget");
printf("msgget succ
");
return 0;
}
删除消息队列:
int msgctl(int msgid,int cmd,struct msqid_ds * buf)
cmd:
IPC_STAT:把msqid_ds结构中的数据设置为消息队列的当前关联值;
IPC_SET:在进程有足够的权限的前提下,把消息队列的当前关联值设置为msgid_ds数据结构中给出的值;
IPC_RMID:删除消息队列
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<sys/un.h>
#include<fcntl.h>
#include<sys/msg.h>
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
}while(0)
int main(void)
{
int msgid;
msgid=msgget(1234,0);
if(msgid==-1)
ERR_EXIT("msgget");
msgctl(msgid,IPC_RMID,NULL);//删除消息队列,msgctl函数 int msgctl(int msgid,int cmd,struct msqid_ds * buf)
return 0;
}
消息队列的数据结构
struct msqid_ds {
struct ipc_perm msg_perm; //IPC对象数据结构,每个IPC对象都有。
time_t msg_stime; //消息队列最后一次发送数据的时间
time_t msg_rtime; //消息队列最后一次接受数据的时间
time_t msg_ctime;
unsigned long __msg_cbytes; //消息队列中当前字节数
msgqnum_t msg_qnum; //消息队列中当前消息总数
msglen_t msg_qbytes; //消息队列所能容纳的最大字节数
pid_t msg_lspid; //最后一个向消息队列发送消息的进程号
pid_t msg_lrpid;
};
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<sys/un.h>
#include<fcntl.h>
#include<sys/msg.h>
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
}while(0)
int main(void)
{
int msgid;
msgid=msgget(1234,0);
if(msgid==-1)
ERR_EXIT("msgget");
printf("megget succ
");
printf("msgid=%d
",msgid);
struct msqid_ds buf;
msgctl(msgid,IPC_STAT,&buf);//获取消息队列状态信息
printf("mode=%o
",buf.msg_perm.mode);//输出权限值
//获取消息队列中当前字节数,当前消息总数,消息队列所能容纳的最大字节数
printf("byte=%ld
number=%d
msgmnb=%d
",buf.__msg_cbytes,(int)buf.msg_qnum,(int)buf.msg_qbytes);
sscanf("600","%o",(unsigned int *)&buf.msg_perm.mode);
msgctl(msgid,IPC_SET,&buf);
printf("mode=%o
",buf.msg_perm.mode);
return 0;
}
消息队列中的每条消息是通过链表方式组织的,每条消息的最大长度不能超过MSGMAX.所有消息字节总和不能超过MSGMNB.系统中消息队列的
总数不能超过MSGMNI
把一条消息添加到消息队列中
int msgsnd(int msqid,const void*msgp,size_t msgsz,int msgflg);
第一个参数:由msgget函数返回的消息队列标识码;第二个参数:一个指针,指针指向准备发送的消息;第三个参数:是msgp指向的消息长度,这个长度不含保存消息类型的那个long int
最后一个参数:msgfkg控制着当前消息队列满或者到达系统上限时将要发生的事:IPC_NOWAIT 表示队列满的时候不等待,而是返回EAGAIN错误。
struct msgbuf *msgp;
struct msgbuf {
long mtype;
char mtext[1];
};
消息大小不能超过MSGMAX;其次它必须以一个long int 长整数开始,接收者将利用这个long int 来确定消息类型。
先用该程序往消息队列中添加数据,再利用下一个程序到指定的消息队列中接收相应类型的消息
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<sys/un.h>
#include<fcntl.h>
#include<sys/msg.h>
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
}while(0)
struct msgbuf {
long mtype; //消息类型
char mtext[1];
};
int main(int argc,char * argv[])
{
if(argc!=3)
{
fprintf(stderr,"Usage:%s <bytes> <type>
",argv[0]);
exit(EXIT_FAILURE);
}
int len=atoi(argv[1]);//消息长度参数
int type=atoi(argv[2]);//消息类型参数
int msgid;
msgid=msgget(1234,0);//打开key为1234的消息队列。必须先创建好消息队列
if(msgid==-1)
ERR_EXIT("msgget");
struct msgbuf *ptr;//消息结构体指针
ptr=(struct msgbuf *)malloc(sizeof(long)+len);
ptr->mtype=type;
//if(msgsnd(msgid,ptr,len,0)<0)
//任意数据,不关心
if(msgsnd(msgid,ptr,len,IPC_NOWAIT)<0)
ERR_EXIT("msgsnd");
return 0;
}
发送完消息后,可以运行第三个程序来查看消队列的状态。例如:./msg_send 200 2 发送200字节消息,类型是2
接受消息队列中的消息:
分析命令行参数其中短参数在getopt定义里分为三种:
1. 不带值的参数,它的定义即是参数本身。
2. 必须带值的参数,它的定义是在参数本身后面再加一个冒号。
3. 可选值的参数,它的定义是在参数本身后面加两个冒号 。
在这里拿上面的"1ac:d::"作为样例进行说明,其中的1,a就是不带值的参数,c是必须带值的参数,该参数的指针赋给optarg.d是可选值的参数。
在实际调用中,'-1 -a -c cvalue -d', '-1 -a -c cvalue -ddvalue', '-1a -ddvalue -c cvalue'都是合法的。这里需要注意三点:
1. 不带值的参数可以连写,象1和a是不带值的参数,它们可以-1 -a分开写,也可以-1a或-a1连写。
2. 参数不分先后顺序,'-1a -c cvalue -ddvalue'和'-d -c cvalue -a1'的解析结果是一样的。
3. 要注意可选值的参数的值与参数之间不能有空格,必须写成-ddvalue这样的格式,如果写成-d dvalue这样的格式就会解析错误。
getopt()每次调用会逐次返回命令行传入的参数。
当没有参数的最后的一次调用时,getopt()将返回-1。
当解析到一个不在optstring里面的参数,或者一个必选值参数不带值时,返回'?'。
当optstring是以':'开头时,缺值参数的情况下会返回':',而不是'?' 。
int getopt(int argc,char * const argv[ ],const char * optstring);
接收消息,返回接收到的字节数。
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
msgid:消息队列ID;
msgp:一个指针,指向准备接收的消息;
msgsz:是msgp指向的消息的长度,不包含类型long int 的长度;
msgtype:它可以实现接受优先级的简单形式.接收消息的类型,发送消息的程序中有消息的类型long int
msgtype=0:返回消息队列第一条消息;
msgtype>0:返回队列第一条类型=msgtype的消息;
msgtype<0:返回队列类型小于等于msgtype绝对值的消息;
可以这么使用这个函数 ./msgrcv -n -t 2 -n表示非阻塞方式,队列为空的时候不阻塞;2是消息类型
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<sys/un.h>
#include<fcntl.h>
#include<sys/msg.h>
#define ERR_EXIT(m)
do
{
perror(m);
exit(EXIT_FAILURE);
}while(0)
#define MSGMAX 8192
struct msgbuf {
long mtype;
char mtext[1];
};
int main(int argc,char * argv[])
{
int flag=0;
int type=0;
int opt;
while(1)
{
opt=getopt(argc,argv,"nt:");
if(opt=='?')
exit(EXIT_FAILURE);//解析到了不认识的参数
if(opt==-1)
break;//所有参数解析完毕
switch (opt)
{
case 'n':
flag|=IPC_NOWAIT;
break;
case 't':
type=atoi(optarg);// -t 2 表示还可以跟一个参数,这个参数存在optarg中
break;
default:
break;
}
}
int msgid;
msgid=msgget(1234,0);
if(msgid==-1)
ERR_EXIT("msgget");
struct msgbuf * ptr;
ptr=(struct msgbuf *)malloc(sizeof(long)+MSGMAX);
ptr->mtype=type;//要接受的消息的类型
int n=0;
if((n=msgrcv(msgid,ptr,MSGMAX,type,flag))<0)
ERR_EXIT("msgsnd");
printf("read %d bytes type=%ld
",n,ptr->mtype);
return 0;
}