目录
一、Linux 中主要的进程间通信方式如下:
二、消息队列函数
(1)msgget函数
功能概述
函数原型
参数解释
返回值
示例
结果
问题
(2) msgsnd函数
功能概述
函数原型
参数说明
返回值
示例
结果
(3)msgrcy函数
功能概述
函数原型
参数说明
返回值
示例
结果 (与上方的消息队列发送结合)
本篇文章开始前我们先来了解一些基本技术
一、Linux 中主要的进程间通信方式如下:
管道:包括无名管道和命名管道。无名管道用于具有亲缘关系的进程间单向通信;命名管道可用于不相关进程间的双向通信,通过路径名访问。
信号:异步通知机制,用于通知进程特定事件发生,进程可自定义信号处理函数或忽略信号。
共享内存:允许多个进程共享同一块物理内存区域,实现高效的数据交换,需结合信号量等同步机制保证数据一致性。
消息队列:进程可向队列发送和接收具有特定格式和类型的消息,实现异步、可靠的通信,不同进程可松耦合通信。
信号量:用于进程间的同步和互斥,通过计数器表示资源可用数量,控制进程对共享资源的访问。
套接字(socket):网络通信机制,也可用于本地进程间通信,本地通信使用 UNIX 域套接字,提供可靠的双向通信,适用于不同主机或同一主机上不同进程间通信。
注:消息队列、共享内存、信号量数组:生命周期和进程无关,归操作系统直接管理。
二、消息队列函数
(1)msgget函数
功能概述
msgget
函数的主要功能是创建一个新的消息队列或者获取一个已经存在的消息队列的标识符。消息队列允许不同的进程通过发送和接收消息来进行通信,是一种强大且灵活的进程间通信方式。
函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
参数解释
key
:这是一个用于标识消息队列的id。key
可以是由 ftok
函数生成的键,也可以是特殊值 IPC_PRIVATE
。
IPC_PRIVATE
:用于创建一个新的、私有的消息队列。这个队列只能由创建它的进程及其子进程访问。通过
ftok
生成的键:可以用于多个进程之间共享同一个消息队列。不同的进程使用相同的路径名和项目 ID 调用ftok
函数,就可以得到相同的key
值,从而访问同一个消息队列。
msgflg
:这是一个标志位,用于指定消息队列的创建和访问权限。它可以是以下标志的组合。
IPC_CREAT
:如果指定的消息队列不存在,则创建一个新的消息队列。
IPC_EXCL
:与IPC_CREAT
一起使用时,如果消息队列已经存在,则msgget
调用会失败并返回 -1。权限标志:例如0666
,用于指定消息队列的访问权限,类似于文件的权限设置。
返回值
成功时,msgget
返回一个非负整数,这个整数就是消息队列的标识符(msgid
),后续的 msgsnd
、msgrcv
等函数将使用这个标识符来操作消息队列。
失败时,返回 -1,并设置 errno
来指示错误类型。
示例
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
using namespace std;
int main()
{
// 如果key不存在就创建新的,如果存在就访问这个已经存在的消息队列
int msgid = msgget((key_t)1001, IPC_CREAT | 0777);
if (msgid == -1)
{
perror("msgget error");
}
return 0;
}
结果
问题
但我们这个有一个问题就是创建了之后就算程序运行结束它也无法消亡我们该怎么办呢。我们使用命令行来查看有哪些方法:
ipcrm -h
第一种办法,使用命令行
ipcrm -Q keyid
第二种办法,直接删除全部
(2) msgsnd函数
功能概述
msgsnd
是一个在 Unix 和类 Unix 系统中用于消息队列操作的系统调用函数,其主要功能是把消息添加到指定的消息队列里。
函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数说明
msqid
:消息队列的标识符,由msgget
函数返回。
msgp
:指向消息缓冲区的指针,此缓冲区包含要发送的消息。消息缓冲区的结构通常如下:struct msgbuf { long mtype; /* 消息类型,必须大于 0 */ char mtext[1]; /* 消息数据 */ };
msgsz
:消息数据部分(mtext
)的字节数,但不是结构体长度就是不包含消息类型mtype
。
msgflg
:控制函数行为的标志。常见的标志有:
IPC_NOWAIT
:若消息队列已满,函数会立即返回-1
,并将errno
设置为EAGAIN
。
0
:若消息队列已满,函数会阻塞,直到有空间可用。
返回值
若成功,返回 0
。
若失败,返回 -1
,并设置 errno
来指示错误类型。
示例
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
using namespace std;
typedef struct messagebuf
{
long mtype;
char mtext[50];
}MSGBUF;
int main()
{
// 如果key不存在就创建新的,如果存在就访问这个已经存在的消息队列
int msgid = msgget((key_t)1001, IPC_CREAT | 0777);
if (msgid == -1)
{
perror("msgget error");
}
else
{
cout << "msgget success" << endl;
MSGBUF buf;
buf.mtype = 1;
sprintf(buf.mtext, "%s", "hello IPC");
if (msgsnd(msgid, &buf, sizeof(buf.mtext), 0) < 0)
{
perror("msgsnd error");
}
else
{
cout << "msgsnd success" << endl;
}
}
return 0;
}
结果
(3)msgrcy函数
注:这是一个阻塞式函数,如果消息队列中没有数据就会阻塞,直到我又发送一个数据到消息队列中才会继续。
功能概述
它是 Unix 和类 Unix 系统中用于消息队列操作的系统调用,主要功能是从指定的消息队列中接收消息。
函数原型
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数说明
msqid
:消息队列的标识符,由msgget
函数返回。
msgp
:指向消息缓冲区的指针,此缓冲区包含要发送的消息。(与上同)
msgsz
:指定要接收的消息数据部分(mtext
)的最大字节数,不包含消息类型mtype
。
msgtyp
:指定要接收的消息类型:
msgtyp == 0
:接收消息队列中的第一条消息。
msgtyp > 0
:接收消息类型为msgtyp
的第一条消息。
msgtyp < 0
:接收消息类型小于或等于msgtyp
绝对值的最小类型的第一条消息。
msgflg
:控制函数行为的标志,常见的标志有:
IPC_NOWAIT
:如果没有符合条件的消息,函数会立即返回-1
,并将errno
设置为ENOMSG
。
MSG_EXCEPT
(仅在msgtyp > 0
时有效):接收类型不等于msgtyp
的第一条消息。
MSG_NOERROR
:如果消息长度超过msgsz
,则截断消息而不产生错误。
返回值
若成功,返回接收到的消息数据部分(mtext
)的字节数。
若失败,返回 -1
,并设置 errno
来指示错误类型。
示例
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
using namespace std;
typedef struct messagebuf
{
long mtype;
char mtext[50];
}MSGBUF;
int main()
{
// 如果key不存在就创建新的,如果存在就访问这个已经存在的消息队列
int msgid = msgget((key_t)1001, IPC_CREAT | 0777);
if (msgid == -1)
{
perror("msgget error");
}
else
{
cout << "msgid=" << msgid << endl;
MSGBUF buf;
if (msgrcv(msgid, &buf, sizeof(buf.mtext), 1, 0) < 0)
{
perror("msgrcv error");
}
else
{
cout << "从消息队列中接收数据成功,数据为:" << buf.mtext << endl;
}
}
return 0;
}
结果 (与上方的消息队列发送结合)
数据取走之后,字节数又变成0