目录
一 消息队列
消息队列是一种进程间的通讯的消息队列,能够独立于读端和写段,如果发送或者接收进程终止了,其中的消息也不会消失,并且进程可以按照类型对消息队列进行读写。
二 消息队列的相关函数
消息队列的函数定义在sys/msg.h头文件中。
2.1 消息队列的创建
int msgget(key_t key, int msgflg);
函数功能:主要是在内核创建一个消息队列。
函数参数:
1.key:主要是用于全局表示这个IPC资源:消息队列的唯一性;
2.msgflg:和信号量semget()函数的sem_flags参数的取值相同。
当该函数创建成功时,会在内核建立一个该消息队列的msgid_ds结构体变量:
struct msqid_ds
{
struct ipc_perm msg_perm;/*消息队列的操作权限*/
time_t msg_stime;/*最后一次调用msgsnd的时间*/
time_t msg_rtime;/*最后一次调用msgrcv的时间*/
time_t msg_ctime;/*最后一次被修改的时间*/
unsigned long__msg_cbytes;/*消息队列中已有的字节数*/
msgqnum_t msg_qnum;/*消息队列中已有的消息数*/
msglen_t msg_qbytes;/*消息队列允许的最大字节数*/
pid_t msg_lspid;/*最后执行msgsnd的进程的PID*/
pid_t msg_lrpid;/*最后执行msgrcv的进程的PID*/
};
2.2 消息的发送
int msgsnd(int msgid, const void* msg_ptr, size_t msg_sz, int msgflg);
函数功能:主要用于向msgid标识的消息队列发送size大小的由msg_ptr所指向的消息。
函数参数:
1.msgid:由msgget()函数返回的消息队列标识符;
2.msg_ptr:发送的消息,具体结构如下所示:
struct msgbuf{
long mtype;
char mtext[512];
};
3.msg_sz:发送的消息msgbuf中mtext字符数组的实际数据长度;
4.msgflg:主要就是IPC_NOWAIT参数,当消息队列满的时候,会阻塞,直到:a.消息队列不满;b.消息队列被进程移除,会返回EIDRM错误;c.该函数被中断后,会返回EINTR错误。如果不设置IPC_NOWAIT参数,则不会阻塞,如果消息队列已满设置errno为EAGAIN。
2.3 消息的接收
int msgrcv(int msgid, void* msg_ptr, size_t msg_sz, long int msg_type, int msgflg);
函数功能:主要用于接收由msgid标识的消息队列中,大小为msg_sz字节,消息类型为msg_type类型的消息,存储在msg_ptr指针指向的结构体msgbuf中。
函数参数:
1.msg_type的取值:
a.当msg_type大于0时,用于获取消息类型mtype为msg_type的消息;
b.当msg_type等于0时,用于获取消息队列第一个消息;
c.当msg_type小于0时,用于获取消息队列中第一个小于msg_type的绝对值的消息。
2.msgflg:主要有如下取值:
a.IPC_NOWAIT:如果消息队列中没有消息,则不阻塞直接返回,并且设置errno为ENOMSG;
b.MSG_EXCEPT:用于获取消息队列第一个非msg_type类型的消息;
c.MSG_NOERROR:当消息的长度大于msg_size,则将多余的部分截断。
2.4 消息的设置
int msgctl(int msgid, int command, msgid_ds* buf);
函数功能:用于对消息队列的属性进行设置。
函数参数:
1.IPC_STAT:用于将消息队列的msgid_ds结构体存储在buf指针指向的地址中;
2.IPC_SET:与IPC_STAT的功能相反;
3.IPC_RMID:将消息队列从内核中移除,唤醒所有等待读写该消息队列的进程。
三 测试案例
一个进程往消息队列里面写入数据,一个进程从消息队列中读出数据:
读进程:
#include<stdio.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#define MSG_KEY 0x1234
#define MSG_SIZE 512
#define MSG_TYPE 123
struct msgbuf{
long mtype;
char mtext[MSG_SIZE];
};
int main()
{
int msg_id = msgget(MSG_KEY, IPC_CREAT|0666);
if(msg_id == -1)
{
printf("创建消息队列失败\n");
return -1;
}
struct msgbuf read_buf;
int nread = msgrcv(msg_id, &read_buf, sizeof(read_buf.mtext), MSG_TYPE, 0);
if(nread == -1)
printf("读消息队列失败\n");
else
printf("读消息队列成功:%s\n", read_buf.mtext);
struct msqid_ds buf;
msgctl(msg_id, IPC_RMID, &buf);
return 0;
}
写进程:
#include<stdio.h>
#include<sys/msg.h>
#include<stdlib.h>
#include<string.h>
#define MSG_KEY 0x1234
#define MSG_SIZE 512
#define MSG_TYPE 123
struct msgbuf{
long mtype;
char mtext[MSG_SIZE];
};
int main()
{
int msg_id = msgget(MSG_KEY, IPC_CREAT|0666);
if(msg_id == -1)
{
printf("创建消息队列失败\n");
return -1;
}
struct msgbuf send_buf = {MSG_TYPE, "这是写进程"};
int nsend = msgsnd(msg_id, &send_buf, sizeof(send_buf.mtext), 0);
if(nsend == -1) printf("读消息队列失败\n");
else printf("写消息队列成功\n");
return 0;
}
测试结果: