system V 标准的进程间通信方式:
消息队列:发送的是带有类型的数据块,实际上是操作系统在内核为我们创建的一个队列,每个进程都可以通过队列的标识符(key)打开这个队列。每一个进程都可以向队列中添加节点或获取节点来进行数据传输。这个队中的节点都有一个类型。
如何传输数据:
组织一个带有类型的的数据块,添加到队列中,其它的进程从队列中获取数据块,也就是说消息队列传输的是一个个带有类型的数据块。
消息队列具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。消息队列是随内核。
消息特征
消息队列是一个全双工通信,可读可写(可以发送数据,也可以接收数据)
消息列队的生命周期随内核
消息队列也有管道⼀样的不足,就是每个消息的最⼤⻓度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有⼀个上限(MSGMNI)
实际中消息队列使用的少的原因:
1.消息结构在两⽅⾯受到制约:
⾸先,它必须⼩于系统规定的上限值;
其次,它必须以⼀个long int⻓整数开始,接收者函数将利⽤这个⻓整数确定消息的类型
2.消息结构参考形式如下:
struct msgbuf {
long mtype;
char mtext[1];
};
1. 创建消息队列int msgget(key_t key,int msgflg);
函数参数 | 含义 |
---|---|
key | 内核中消息队列的标识 |
msgflg | IPC_CREAT:不存在则创建,存在则打开;IPC_EXCL:与IPC_CREAT同用时,若存在则报错;mode 权限 |
返回值 | 代码操作的句柄 失败:-1 |
2、发送数据(插入节点)、接收数据(获取节点)msgsnd/msgrcv
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
函数参数 | 含义选项A |
---|---|
msqid | msgget返回的操作句柄 |
*msgp: | 接收数据的结构体指针,需要自己定义 |
msgsz | 用于指定接受的最大的数据长度,不包含mtype |
msgtyp | 用于指定接收数据的类型 |
msgflag | 0-默认阻塞式获取数据;MSG_NOERROR接收的mtext长度大于msgsz时候自动截断 |
- msgflg的另一个选项:MSG_NOWAIT消息队列中没有请求信息时候就立即返回,系统称该错误信息为ENOMSG
- msgtype :
=0取队列中的第一个节点,不分类型,不分优先级
>0取指定的类型的第一个节点
<0取小于msgtype绝对值类型的第一个节点
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
没有发送类型选项。
3、释放消息队列msgctl
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
cmd选项:IPC_RMID删除消息队列,msqid_ds:默认NULL
操作系统中IPC相关命令:
ipcs -[qms] //查看ipc信息
-q 查看队列
-m 查看共享内存
-s 查看信号量
ipcrm - [qms] msgid 删除指定的ipc队列/共享内存/信号量
消息队列服务端
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
//定义一个msg的标识符
#define KEY 0x167
//定义接受/发送数据类型
#define TYPE_S 1
#define TYPE_C 2
//定义消息队列结点
struct msgbuf{
long mtype; //消息队列是带有数据类型的数据块
char mtext[100];
}buf;
int main()
{
//1、创建消息队列,如果已经有了就打开
umask(0);
int msgid=-1;
msgid=msgget(KEY,IPC_CREAT|0664);
if(msgid<0){
perror("msgget error");
return -1;
}
//创建成功后,进行数据交互
while(1)
{
//2、服务端先接受数据
int rec=msgrcv(msgid,&buf,110,TYPE_C,0);
if(rec<0){
perror("msgrcv error");
return -1;
}else
printf("client say:%s\n",buf.mtext);
//3、发送端回复信息
memset(&buf,0x00,sizeof(buf));
buf.mtype=TYPE_S;
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
scanf("%s",&buf.mtext);
msgsnd(msgid,&buf,100,0);
}
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
消息队列客户端
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<string.h>
//定义一个msg的标识符
#define KEY 0x167
//定义接受/发送数据类型
#define TYPE_S 1
#define TYPE_C 2
//定义消息队列结点
struct msgbuf{
long mtype; //消息队列是带有数据类型的数据块
char mtext[100];
}buf;
int main()
{
//1、创建消息队列,如果已经有了就打开
umask(0);
int msgid=-1;
msgid=msgget(KEY,IPC_CREAT|0664);
if(msgid<0){
perror("msgget error");
return -1;
}
//创建成功后,进行数据交互
while(1)
{
//4、客户端先发送信息
memset(&buf,0x00,sizeof(buf));
buf.mtype=TYPE_C;
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
scanf("%s",&buf.mtext);
msgsnd(msgid,&buf,100,0);
//2、然后接受数据
memset(&buf,0x00,sizeof(buf));
int rec=msgrcv(msgid,&buf,110,TYPE_S,0);
if(rec<0){
perror("msgrcv error");
return -1;
}else
printf("server say:%s\n",buf.mtext);
}
msgctl(msgid,IPC_RMID,NULL);
return 0;
}