定义:是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。有写权限的进程可以向消息队列中添加新消息;有读权限的进程则可以从消息队列中读走消息。消息本质上是一种数据结构。暂且这样,先要会用,会用了可以继续研究内部实现过程。用都不会用,太纠结实现原理,在有限时间内,是得不偿失的。
下面只对用到的函数参数分析及代码解析,最后给一个编程思路。
下面涉及两个文件,msgsend.c与msgreceive.c
基本函数:msgrcv(接收)、msgsnd(发送)、msgget(新建)、msgctl(删除)
(1)新建消息队列
//创建消息队列--类比于open,其返回的标识id,用于msgrcv(接收)、msgsnd(发送)
int msgget(key_t key, int msgflg);
参数:
(1)key:消息队列关联的标识符,本质是整数,可以弄个整数强制转化下就可以了,如(key_t)1234
(2)msgflg:消息队列的建立标志和存取权限
msg = msgget((key_t)1234, 0777|IPC_CREAT); //IPC_CREAT没有就创建及存取权限s
if(msg == -1)
{
fprintf(stderr, "The filure code is %d!!!\n",errno); //errno--number of last error
exit(EXIT_FAILURE);
}
(2)消息队列的发送
//消息队列的发送--类比于write
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
//这个结构体要用户自己写一个,只要第一个参数值大于0,第二个是字符数组,都可以了,如:
#define BUF_TEXT 512
struct msg_st
{
long msg_type; //标志位
char msg_text[BUF_TEXT]; //发送数据缓冲区
};
#include
#include
//msgget
#include
#include
#include
//exit头文件
#include
#include
//errno头文件
#include
#include
#define BUF_TEXT 512
/****************************************************************************************
** 消息队列
** msgget():创建消息队列--类比于open
** int msgget(key_t key, int msgflg);
** key:
** 消息队列关联的标识符
** msgflg:消息队列的建立标志和存取权限
** IPC_CREAT:如果内核中没有此队列则创建它
** 当IPC_EXCL和IPC_CREAT一起使用时,如果队列已经存在,则失败
** RETURN VALUE
** 执行成功则返回消息队列的标识符(a nonnegative integer-非负整数),否则返回-1
** 注意:
** key_t本质是整数,你自己弄个整数强制转化下就可以了,如(key_t)1234
** msgsnd():消息队列的发送--类比于write
** int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** *msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 这里是void*,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgflg: 标志位
** RETURN VALUE
** On success, zero is returned. On error, -1 is returned
** msgrcv():消息队列的接受--类比于read
** ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** *msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 这里是void*,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgtyp: msgtyp等于0 ,则返回队列的最早的一个消息
** msgtyp大于0,则返回其类型为mtype的第一个消息
** msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息
** msgflg: 标志位,如果为0,表示忽略该标志位
** RETURN VALUE
** 成功返回数据长度,错误返回-1
** fgets():从指定流中读出size-1个字符,若读入新行,则存在buffer中,最后要以NULL结尾
** char *fgets(char *s, int size, FILE *stream);
** stream: 几种标准的流/文件句柄
** stpcpy(): 字符串的复制
** char *stpcpy(char *dest, const char *src);
** strncmp(): 字符串比较
** char *strncmp(char *dest, const char *src, size_t n);
****************************************************************************************/
//msgsnd/msgrcv 第二个参数
struct msg_st
{
long msg_type; //标志位
char msg_text[BUF_TEXT]; //发送数据缓冲区
};
int main(void)
{
struct msg_st data;
int msg = -1; //标识id
int running = 1;
char buffer[BUFSIZ]; //系统常量BUFSIZ是8192--定义在stdio.h中
msg = msgget((key_t)1234, 0777|IPC_CREAT); //IPC_CREAT没有就创建及存取权限s
if(msg == -1)
{
fprintf(stderr, "The filure code is %d!!!\n",errno); //errno--number of last error
exit(EXIT_FAILURE);
}
while(running)
{
printf("Please enter data: \n");
fgets(buffer, BUFSIZ, stdin); // 标准输入向buffer获取BUFSIZ-1个字符
data.msg_type = 1; //标志置1,表示要通信了。其他数也可以
stpcpy(data.msg_text, buffer); //将buffer的数据复制到结构体的msg_text中
if(msgsnd(msg, (void *)&data, BUF_TEXT, 0) == -1) //发送数据到data结构体的数组中
{
fprintf(stderr, "magsnd error!!!\n");
exit(EXIT_FAILURE);
}
if(strncmp(data.msg_text, "end", 3) == 0) //判断字符串是否相等,自己弄个结束标志
{
running = 0; //推出while
}
sleep(1);
}
exit(EXIT_SUCCESS);
}
(1)新建消息队列
和msgsend.c一样,都需要打开同一个消息队列才可以通信。见上
(2)消息队列的接收
msgrcv():消息队列的接受--类比于read
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
(3)断开消息队列的连接
msgctl():消息队列的控制函数,里面有一项可以删除消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//断开消息队列的连接
if(msgctl(msg, IPC_RMID, 0) == -1) //msgctl删除消息队列
{
fprintf(stderr, "magctl error code %d !!!\n",errno);
exit(EXIT_FAILURE);
}
//msgreceive.c
#include
#include
//msgget
#include
#include
#include
//exit头文件
#include
#include
//errno头文件
#include
#include
/****************************************************************************************
** 消息队列
** msgrcv():消息队列的接受--类比于read
** ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
** msqid : 消息队列的标识码(msgget返回的id)
** *msgp : 指向消息缓冲区的指针,需要用户自己定义一个结构体,系统没有提供(满足第一元素要大于0,第二个数字符数组)
** 这里是void*,要强制转换下,最好这样。
** msgsz : 消息的长短
** msgtyp: msgtyp等于0 ,则返回队列的最早的一个消息,这里给0
** msgtyp大于0,则返回其类型为mtype的第一个消息
** msgtyp小于0,则返回其类型小于或等于mtype参数的绝对值的最小的一个消息
** msgflg: 标志位,如果为0,表示忽略该标志位
** RETURN VALUE
** On success, zero is returned. On error, -1 is returned
** msgctl():
** int msgctl(int msqid, int cmd, struct msqid_ds *buf);
** msqid : 消息队列的标识码(msgget返回的id)
** cmd :
** IPC_RMID: 立即断开连接
** RETURN VALUE
** On success, IPC_STAT, IPC_SET, and IPC_RMID return 0.On error, -1 is returned
** fgets():从指定流中读出size-1个字符,若读入新行,则存在buffer中,最后要以NULL结尾
** char *fgets(char *s, int size, FILE *stream);
** stream: 几种标准的流/文件句柄
** stpcpy(): 字符串的复制
** char *stpcpy(char *dest, const char *src);
** strncmp(): 字符串比较
** char *strncmp(char *dest, const char *src, size_t n);
****************************************************************************************/
//msgsnd/msgrcv 第二个参数
struct msg_st
{
long msg_type; //标志位
char msg_text[BUFSIZ]; //系统常量BUFSIZ是8192--定义在stdio.h中
};
int main(void)
{
struct msg_st data;
int msg = -1; //标识id
int running = 1;
char buffer[BUFSIZ];
long int msgtype = 0; //这里给0,返回队列的最早的一个消息
//打开消息队列
msg = msgget((key_t)1234, 0777|IPC_CREAT); //IPC_CREAT没有就创建及存取权限s
if(msg == -1)
{
fprintf(stderr, "The filure code is %d!!!\n",errno); //errno--number of last error
exit(EXIT_FAILURE);
}
//接受消息队列的数据---以end结束
while(running)
{
if(msgrcv(msg, (void *)&data, BUFSIZ, msgtype, 0) == -1) //将结构体中数据通过msgrcv接收
{
fprintf(stderr, "magcve error code %d !!!\n",errno);
exit(EXIT_FAILURE);
}
printf("You just wrote:\n%s\n",data.msg_text);
if(strncmp(data.msg_text, "end", 3) == 0) //以end结束
{
running = 0;
}
}
//断开消息队列的连接
if(msgctl(msg, IPC_RMID, 0) == -1) //msgctl删除消息队列
{
fprintf(stderr, "magctl error code %d !!!\n",errno);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}