Linux进程间通信——使用System V 消息队列

时间:2023-03-09 08:09:08
Linux进程间通信——使用System V 消息队列

消息队列

消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。我们可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。

Linux用宏MSGMAXMSGMNB来限制一条消息的最大长度和一个队列的最大长度。

在Linux中使用消息队列

Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间的通信。

msgget 函数

创建和访问一个消息队列 :

原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgget(key_t key, int msgflag);

参数

key:某个消息队列的名字,用ftok()产生

msgflag:有两个选项IPC_CREAT和IPC_EXCL,单独使用IPC_CREAT,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。

返回值

成功返回一个非负整数,即消息队列的标识码,失败返回-1。

ftok 函数

原型

#include <sys/types.h>
#include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id);

调用成功返回一个key值,用于创建消息队列,如果失败,返回-1。

msgctl 函数

消息队列的控制函数

原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf);

参数

msqid:由msgget函数返回的消息队列标识码

cmd:有三个可选的值,在此我们使用IPC_RMID

IPC_STAT 把msqid_ds结构中的数据设置为消息队列的当前关联值
IPC_SET 在进程有足够权限的前提下,把消息队列的当前关联值设置为msqid_ds数据结构中给出的值
IPC_RMID 删除消息队列

返回值

成功返回0,失败返回-1。

msgsnd 函数

把一条消息添加到消息队列中

原型

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数

msgid:由msgget函数返回的消息队列标识码

msgp:指针指向准备发送的消息

msgze:msgp指向的消息的长度(不包括消息类型的long int长整型)

msgflg:默认为0

返回值

成功返回0,失败返回-1

消息结构一方面必须小于系统规定的上限,另一方面必须以一个long int长整型开始,接受者以此来确定消息的类型

struct msgbuf
{
long mtye;
char mtext[1];
};

msgrcv 函数

是从一个消息队列接受消息

原型

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

参数

与msgsnd相同

返回值

成功返回实际放到接收缓冲区里去的字符个数,失败返回-1

常用命令

显示IPC资源

ipcs -q

Linux进程间通信——使用System V 消息队列

手动删除IPC资源

ipcrm

消息最大长度上限(MSGMAX)

cat /proc/sys/kernel/msgmax

系统上消息队列的总数上限(MSGMNI)

cat /proc/sys/kernel/msgmni

每个消息队列的总的字节数(MSGMNB)

cat /proc/sys/kernel/msgmnb

Linux进程间通信——使用System V 消息队列

代码示例

定义一个 msgque.h 文件

#ifndef __MSGQUE__H__
#define __MSGQUE__H__ #ifdef __cplusplus
extern "C"
{
#endif #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <getopt.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <pthread.h>
#include <poll.h>
#include <sys/msg.h> #define MAXLEN 1024
#define MSG_KEY_DIR "/tmp" typedef struct
{
long Type;
char Content[MAXLEN];
}MsgInfo; int CreateMessage(const char*pathname,int proj_id);
int GetMessage(const char*pathname,int proj_id);
int SendMessage(int msgid,const char* msg,int type);
int ReceiveMessage(int msgid,char* msg,int type);
int DestoryMessage(int msgid); #ifndef MSG
#define MSG(fmt...) \
do {\
printf("{%s}-[%s]-%d: ", __FILE__,__FUNCTION__, __LINE__);\
printf(fmt);\
}while(0)
#endif #ifdef __cplusplus
}
#endif #endif

定义 msgque.c 文件

# include "msgque.h"

int CreateMessage(const char*pathname,int proj_id)
{
key_t key = ftok(pathname,proj_id);
int ret = 0; if((ret=msgget(key,IPC_CREAT|0666))==-1)
{
perror("Message Create Error: \r\n");
return -1;
} return ret;
} int GetMessage(const char*pathname,int proj_id)
{
key_t key = ftok(pathname,proj_id);
int ret = 0; if((ret=msgget(key,IPC_CREAT))==-1)
{
perror("Message Get Error: \r\n");
return -1;
} return ret;
} int SendMessage(int msgid,const char* msg,int type)
{
MsgInfo buf;
buf.Type = type;
strcpy(buf.Content,msg);
if(msgsnd(msgid,&buf,sizeof(buf.Content),0) == -1)
{
MSG("Msg Send Error\n");
DestoryMessage(msgid);
return -1;
} return 0;
} int ReceiveMessage(int msgid,char* msg,int type)
{
MsgInfo buf;
if(msgrcv(msgid,&buf,sizeof(buf.Content),type,0)==-1)
{
MSG("Msg Recv Error\n");
DestoryMessage(msgid);
return -1;
}
strcpy(msg,buf.Content); return 0;
} int DestoryMessage(int msgid)
{
if(msgctl(msgid,IPC_RMID,NULL) == -1)
{
MSG("Msg Destroy Error\n");
return -1;
} return 0;
} int MessageCommon(key_t key,int flag)
{
int ret = 0;
if((ret=msgget(key,flag))==-1)
{
perror("MessageCommon Error: ");
}
return ret;
}

定义send.c 文件

# include "./msgque/msgque.h"

int main()
{
int running = 1;
char buffer[MAXLEN];
MsgInfo data; int masgid = CreateMessage(MSG_KEY_DIR,0x01); while(running)
{
printf("Enter data : ");
fgets(buffer, MAXLEN, stdin); SendMessage(masgid,buffer,1); if(strncmp(buffer, "end", 3) == 0)
{
DestoryMessage(masgid);
running = 0;
} usleep(100000);
} return 0;
}

定义recv.c 文件

# include "./msgque/msgque.h"

int main()
{
int running = 1;
char buffer[MAXLEN]; int masgid = GetMessage(MSG_KEY_DIR,0x01); while(running)
{
ReceiveMessage(masgid,buffer,1); printf("You wrote: %s\n",buffer); if(strncmp(buffer, "end", 3) == 0)
{
running = 0;
} usleep(100000);
} exit(EXIT_SUCCESS);
}

测试结果:

Linux进程间通信——使用System V 消息队列