今天我们来分享一下进程通行(IPC)-实现消息队列。
消息队列由操作系统提供一个链表(也就是说消息队列需要操作系统接口),以链表节点为一个数据块(有类型),基于消息,每条消息有上限且消息的总数也是有限的。
与管道通行的区别是,管道通信以字节流为通信单位,消息队列是以有类型的数据块为通信单位。
消息队列实现原理:
一个进程建立消息队列(本文为serves),另一个进程(本文为client)打开该消息队列即可。此后两个进程可以相互读写以此来进行通信。
消息队列实现步骤:
1》建立(打开)消息队列
2》发送消息/接收消息
3》接收消息/发送消息
4》销毁消息队列(谁建立谁销毁)
进行传递消息的数据块(结构体)如下示:
struct msgbuf{
long mtype;//消息的发起者的类型(标志)
char mtext[1024];//消息内容
};
消息队列是随内核的,除了需要调用系统接口去建立消息队列,还需要调用系统接口去销毁消息队列。
最后,介绍关于查看消息队列和销毁消息队列的系统命令,截图如下:
代码和运行结果如下:
Commom.h
#ifndef _COMMOM_H_
#define _COMMOM_H_
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#include<unistd.h>
struct msgbuf{
long mtype;
char mtext[1024];
};
#define PATHNAME "."
#define PROJ_ID 0x6666
#define SERVE 1
#define CLIENT 2
int CreatMsgQueue();
int GetMsgQueue();
int SendMsgQueue(int msgid, int who, char* msg);
int RecvMsgQueue(int msgid, int recvtype, char* out);
int DestroyMsgQueue(int msgid);
#endif
Commom.c
#include"commom.h"
int commMsgQueue(int flags)
{
key_t keys = ftok(PATHNAME, PROJ_ID);
if(keys<0){
perror("ftok");
return -2;
}
int msgid = msgget(keys, flags);
if(msgid <0){
perror("msgget");
return -1;
}
return msgid;
}
int CreatMsgQueue()
{
return commMsgQueue(IPC_CREAT|IPC_EXCL);
}
int GetMsgQueue(){
return commMsgQueue(IPC_CREAT);
}
int SendMsgQueue(int msgid, int who, char* msg){
struct msgbuf buf;
buf.mtype = who;
strcpy(buf.mtext,msg);
Int flag = msgsnd(msgid,(void*)&buf, sizeof(buf.mtext),0);
if(flag<0){
perror("msgsnd");
return -4;
}
return 0;
}
int RecvMsgQueue(int msgid, int recvtype, char* out){
struct msgbuf buf;
ssize_t s = msgrcv(msgid,(void*)&buf, sizeof(buf.mtext), recvtype, 0);
if(s<0){
perror("msgvcv");
return -5;
}
strcpy(out, buf.mtext);
return s;
}
int DestroyMsgQueue(int msgid){
int flag = msgctl(msgid, IPC_RMID, NULL);
if(flag<0){
perror("");
return -3;
}
return 0;
}
Client.c
#include"commom.h"
#include"commom.c"
int main(){
int msgid = GetMsgQueue();
char msg[1024];
while(1){
int r = RecvMsgQueue(msgid, SERVE,msg);
if(r<0){
perror("recv wrong");
return -3;
}
printf("serve say:%s\n", msg);
printf("please write: ");
fflush(stdout);
ssize_t s=read(0, msg, sizeof(msg)-1);
if(s<0){
perror("fread");
return -1;
}
msg[s-1] = 0;
int k = SendMsgQueue(msgid, CLIENT, msg);
if(k<0){
perror("send wrongs");
return -2;
}
}
return 0;
}
Serves.c
#include"commom.h"
#include"commom.c"
int main(){
umask(0);
int msgid = CreatMsgQueue();
char msg[1024];
while(1){
printf("please write: ");
fflush(stdout);
ssize_t s=read(0, msg, sizeof(msg)-1);
if(s<0){
perror("fread");
return -1;
}
msg[s-1] = 0;
int k = SendMsgQueue(msgid, SERVE, msg);
if(k<0){
perror("send wrongs");
return -2;
}
int r = RecvMsgQueue(msgid, CLIENT,msg);
if(r<0){
perror("recv wrong");
return -3;
}
printf("client say:%s\n", msg);
}
DestroyMsgQueue(msgid);
return 0;
}
Makefile
.PHONY:all
all:client serve
client:client.c commom.h
gcc -o $@ $^
serve:serves.c commom.h
gcc -o $@ $^
.PHONY:clean
clean:
rm -f client serve
运行界面(先运行serve再运行client)
分享如上,如有错误望指针,共同学习!