System V 消息队列(1)
一、函数
头文件列表
<sys/types.h>
<sys/ipc.h>
<sys/msg.h>
msgget
原型
int msgget(key_t key, int oflag);
函数功能
创建一个新的消息队列或者访问一个已存在的消息队列。
参数
key可以为IPC_PRIVATE,表示创建一个新队列;
oflag可以为IPC_CREAT, IPC_EXCL, O_RDONLY...,创建一个新队列时,会初始化msqid_ds。
返回值
成功返回非负整数;失败返回-1,设置errno
msgsnd
原型
int msgsnd(int msqid, const void *ptr, size_t len, int flag);
函数功能
给描述符msqid指向的消息队列发送消息,大小为len,内容存放在ptr中.
参数
ptr指向的数据定义成以下类型
typedef struct {
long mtype; /* 消息类型 */
char mdata[100]; /* 消息内容 */
...
}msg;
len=sizeof(msg) - sizeof(long)
flag为0或者IPC_NOWAIT,IPC_NOWAIT设置不阻塞
返回值
成功返回0;失败返回-1,设置errno
msgrcv
原型
ssize_t msgrcv(int msqid, void *ptr, size_t len, long type, int
flag);
函数功能
从队列读取消息
参数
ptr指向msg结构体
len指示msg中数据的长度
type的值:
0:返回队列中最早的消息
>0:返回类型为type的第一个消息
<0:返回类型值<=|type|的消息中类型值最小的第一个消息
flag的值:
0:没有所要求取的消息时,阻塞
IPC_NOWAIT:不阻塞
IPC_NOERROR:当所接收消息的数据部分大于len参数时,截断数据部分,不返
回错误,否则返回一个E2BIG错误
返回值
成功返回消息的字节数,失败返回-1
msgctl
原型
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数功能
控制队列操作
参数
cmd的值:
IPC_STAT: 返回队列的当前msqid_ds结构体
IPC_SET: 设置队列的msqid_ds的部分成员:msg_perm.{uid,gid,mode}
IPC_RMID: 删除消息队列,里面的任何消息都被丢弃
IPC_INFO,MSG_INFO,MSG_STAT为linux所特有
返回值
成功返回0,失败返回-1
二、系统限制
每个消息的最大字节数
/proc/sys/kernel/msgmax 65536
队列的最大字节数
/proc/sys/kernel/msgmnb 65536
系统范围的最大队列数
/proc/sys/kernel/msgmni 16
一、msgctl程序举例
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <stdio.h>
#define SVMSG_MODE 0660
struct msgbuf{
int msgtype; //消息的类型
char msgdata[100]; //消息的数据
};
int main(int argc, char **argv)
{
int msqid; //返回创建消息队列的编号
struct msqid_ds info;
/*
消息队列状态
struct msqid_ds
{
struct msqid_ds {
struct ipc_perm msg_perm;
struct msg *msg_first; //* first message on queue,unused
struct msg *msg_last; //* last message in queue,unused
__kernel_time_t msg_stime; //* last msgsnd time
__kernel_time_t msg_rtime; //* last msgrcv time
__kernel_time_t msg_ctime; //* last change time
unsigned long msg_lcbytes; //* Reuse junk fields for 32 bit
unsigned long msg_lqbytes; //* ditto
unsigned short msg_cbytes; //* current number of bytes on queue
unsigned short msg_qnum; //* number of messages in queue
unsigned short msg_qbytes; //* max number of bytes on queue
__kernel_ipc_pid_t msg_lspid; //* pid of last msgsnd
__kernel_ipc_pid_t msg_lrpid; //* last receive pid
};
*/
struct msgbuf buf; //存放消息的信息
msqid = msgget(IPC_PRIVATE,SVMSG_MODE|IPC_CREAT);
//两个参数,第一个是表示创建,第二个是flag标记符号
//给消息队列的内容和消息类型赋值
buf.msgtype=1;
buf.msgdata[0]=1;
msgsnd(msqid, &buf, 1, 0);
//发送编号为msqid的消息的内容长度为1的消息,类型为0,结构体是buf
msgctl(msqid, IPC_STAT, &info);
//操作编号为msqid的消息,操作对象为当前结构体,结构体的内容为info
printf("read-write:%03o, cbytes=%lu, qnum=%lu,qbytes=%lu\n",
info.msg_perm.mode &0777,info.msg_cbytes, info.msg_qnum,info.msg_qbytes);
system("ipcs -q"); //显示所有消息队列
msgctl(msqid,IPC_RMID,NULL);
exit(0);
return 0;
}
二、创建、发送、接收程序举例
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <stdio.h>
#include <getopt.h>
#define SVMSG_MODE 0660
#define MAXMSG 255
//定义了消息的类型和内容
struct msgbuf {
int msgtype;
char msgdata[100];
};
int main(int argc, char **argv)
{
int msqid,receive; //返回的是消息队列的编号
struct msqid_ds info,info2; //定义消息的状态的结构体,在创建的时候会初始化
struct msgbuf buf,buf2; //定义消息类型和内容结构体对象
msqid = msgget(IPC_PRIVATE,SVMSG_MODE|IPC_CREAT); //创建消息
buf.msgtype = 1; //消息类型和内容赋值
buf.msgdata[0]=1;
msgsnd(msqid,&buf,1,0); //发送消息
receive=msgrcv(msqid,&buf2,MAXMSG,1,0); //接受消息,并且把消息的编号记住
printf("read %d bytes,type= %ld\n",receive,buf2.msgtype); //读出消息的相关信息
system("ipcs -q"); //显示进程当前的消息信息
return 0;
}
三、一个服务器和客户端的程序举例
服务端
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <errno.h>
#define SVMSG_MODE 0660
#define MSQ_KEY1 1234L
#define MSQ_KEY2 2345L
#define MAXMSGDATA 255
struct msg_t{
int mtype;
int mlen;
char mdata[100];
};
void server(int rdid, int wrid) {
FILE *fp;
char *ptr;
pid_t pid;
ssize_t n;
struct msg_t msg;
for (;;) {
msg.mtype = 1;
if ((n = msgrcv(rdid, &msg,MAXMSGDATA,1,0)) == 0) {
printf("pahtname missing");
continue;
}
msg.mdata[n] = '\0';
if ((ptr = strchr(msg.mdata, ' ')) == NULL) {
printf("bogus request: %s\n", msg.mdata);
continue;
}
*ptr++ = '\0';
pid = atoi(msg.mdata);
msg.mtype = pid;
if ((fp = fopen(ptr, "r")) == NULL) {
snprintf(msg.mdata + n, sizeof(msg.mdata) - n, "can't open, %s\n",
strerror(errno));
msg.mlen = strlen(ptr);
memmove(msg.mdata, ptr, msg.mlen);
msgsnd(wrid, &msg,msg.mlen,0);
} else {
while (fgets(msg.mdata, MAXMSGDATA, fp) != NULL) {
msg.mlen = strlen(msg.mdata);
msgsnd(wrid, &msg,msg.mlen,0);
}
fclose(fp);
}
msg.mlen = 0;
msgsnd(wrid, &msg,msg.mlen,0);
}
}
int main(int argc, char *argv[]) {
int rdid, wrid;
rdid = msgget(MSQ_KEY1, 0644 | IPC_CREAT);
wrid = msgget(MSQ_KEY2, 0644 | IPC_CREAT);
server(rdid, wrid);
system("ipcs -q");
printf("OK");
exit(EXIT_SUCCESS);
}
客户端
/*
* cient.c
*
* Created on: Sep 15, 2011
* Author: tanciping
*/
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <errno.h>
#define SVMSG_MODE 0660
#define MSQ_KEY1 1234L
#define MSQ_KEY2 2345L
#define MAXMSGDATA 255
#define STDOUT_FILEENO "/home/tanciping/Desktop/xx"
struct msg_t {
int mtype;
int mlen;
char mdata[100];
};
void client(int rdid, int wdid) {
size_t len;
ssize_t n;
char *ptr;
struct msg_t msg;
snprintf(msg.mdata,MAXMSGDATA,"%ld",(long)getpid());
len = strlen(msg.mdata);
ptr=msg.mdata+len;
fgets(ptr,MAXMSGDATA-len,stdin);
len = strlen(msg.mdata);
if(msg.mdata[len-1]=='\n')
len--;
msg.mlen=len;
msg.mtype=1;
msgsnd(wdid,&msg,msg.mlen,0);
while((n==msgrcv(rdid,&msg,MAXMSGDATA,msg.mtype,0))>0)
write(STDOUT_FILEENO,msg.mdata,n);
}
int main() {
int rdid,wrid;
rdid = msgget(MSQ_KEY1, 0644 | IPC_CREAT);
wrid = msgget(MSQ_KEY2, 0644 | IPC_CREAT);
client(rdid, wrid);
system("ipcs -q");
printf("OK");
exit(EXIT_SUCCESS);
}
四、消息队列的限制
msgmax 每个消息的最大字节数
msgmnb 任何一个消息队列上的最大字节数
msgmni 系统范围的最大消息队列数
msgtql 系统范围的最大消息数