Linux 下的 msg.h 头文件详解 (msg.h linux)

在 Linux 系统中,msg.h 头文件是消息队列的头文件,主要包含了建立、关闭、发送和接收消息的相关函数的声明。消息队列是多个进程之间进行异步通信的一种方式,常用于进程间通信(IPC)。

本文将对 msg.h 头文件进行详细讲解,包括消息队列的概念、头文件的结构和函数使用方法等。

一、消息队列的概念

消息队列是一种进程间通信的方式,它是一段共享内存,进程可以通过它来传递消息。多个进程可以同时往同一个消息队列中发送消息和从中读取消息,并且每个消息都有一个类型标识。

消息队列有以下几个特点:

1. 消息队列是按照先进先出的规则进行消息的处理。

2. 消息队列中的消息的大小可以自定义,但更大值受系统的限制。

3. 每个消息都有一个类型标识,可以根据类型来选择需要处理的消息。

4. 消息队列适合于进程间的数据量较小,但操作频繁的场景。

5. 消息队列是一种异步通信的方式,不需要等待对方的响应。

二、头文件结构

msg.h 头文件主要包含了以下几个结构体和宏定义:

1. struct msgbuf

该结构体用于保存消息队列中的消息,结构体的定义如下:

“`

struct msgbuf {

long mtype; // 消息类型标识

char mtext[1]; // 消息内容

};

“`

其中,mtype 为消息类型标识,是一个大于 0 的长整型数值,用于区分不同类型的消息。mtext 为消息内容,是一个字符数组,可以保存任意长度的消息。

在使用消息队列时,需要根据实际情况定义结构体的长度,例如:

“`

struct msgbuf {

long mtype; // 消息类型标识

char mtext[1024]; // 消息内容

};

“`

2. struct msqid_ds

该结构体用于保存消息队列的属性,结构体的定义如下:

“`

struct msqid_ds {

struct ipc_perm msg_perm; // 消息队列的权限信息

time_t msg_stime; // 最后一次写入消息队列的时间

time_t msg_rtime; // 最后一次读取消息队列的时间

time_t msg_ctime; // 消息队列的创建时间

unsigned long msg_cbytes; // 消息队列中当前的字节数

unsigned long msg_qnum; // 消息队列中当前的消息数

unsigned long msg_qbytes; // 消息队列中允许的更大字节数

pid_t msg_lspid; // 最后写入消息队列的进程 ID

pid_t msg_lrpid; // 最后读取消息队列的进程 ID

};

“`

其中,msg_perm 是消息队列的权限信息,包括拥有者 ID、群组 ID 和权限标志等信息。msg_stime、msg_rtime 和 msg_ctime 分别表示最后一次写入、读取和创建消息队列的时间。msg_cbytes 表示消息队列中当前的字节数,msg_qnum 表示消息队列中当前的消息数,而 msg_qbytes 则表示消息队列中允许的更大字节数。msg_lspid 和 msg_lrpid 分别表示最后写入和读取消息队列数据的进程 ID。

3. IPC_PRIVATE

IPC_PRIVATE 是一个宏定义,用于表示创建一个新的消息队列,其定义如下:

“`

#define IPC_PRIVATE ((__kernel_key_t)0)

“`

当使用 IPC_PRIVATE 作为 key 值来创建消息队列时,系统将会为其随机生成一个键值,并将该键值作为消息队列的标识符,是一个唯一的值。这种方式创建的消息队列只能在父子进程之间进行通信。

4. IPC_CREAT

IPC_CREAT 是一个宏定义,用于表示创建一个新的消息队列或获取一个已有的消息队列,其定义如下:

“`

#define IPC_CREAT 001000 // 创建新的队列或获取已有队列

#define IPC_EXCL 002023 // 与IPC_CREAT一同使用,用于避免消息队列编号冲突

“`

当使用 IPC_CREAT 和一个正整数 key 配合使用,系统会在内核的消息队列中通过该 key 值查找是否已经存在一个具有相同 key 值的消息队列。如果不存在,则创建一个新的消息队列,并返回该消息队列的标识符;如果已经存在,则返回该消息队列的标识符。当同时使用 IPC_CREAT 和 IPC_EXCL 标志时,如果已经存在一个具有相同 key 值的消息队列,则创建操作将失败,返回 -1。

三、消息队列相关函数

msg.h 头文件中包含了多个函数,用于创建、添加、获取和删除消息队列。其中,常用函数有:

1. int msgget(key_t key, int msg);

该函数用于创建或获取一个消息队列,其参数 key 用于指定消息队列的键值,msg 用于指定消息队列的访问权限和创建方式。返回消息队列的标识符,出错返回 -1。

2. int msgsnd(int msqid, const void *msgp, size_t msgsz, int msg);

该函数用于向指定消息队列中添加消息,其参数 msqid 为消息队列的标识符,msgp 为消息的指针,msgsz 为消息的长度,msg 为消息的标志。返回成功添加消息的长度,出错返回 -1。

3. ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msg);

该函数用于从指定消息队列中读取消息,其参数 msqid 为消息队列的标识符,msgp 为消息的指针,msgsz 为消息的长度,msgtyp 为消息类型标识,msg 为消息的标志。返回读取到的消息的长度,出错返回 -1。

4. int msgctl(int msqid, int cmd, struct msqid_ds *buf);

该函数用于控制指定消息队列的属性,其参数 msqid 为消息队列的标识符,cmd 为操作命令,buf 为消息队列的属性结构体指针。返回成功为 0,出错返回 -1。

其中,cmd 可以设置为以下值:

– IPC_RMID:删除指定的消息队列;

– IPC_STAT:获取指定的消息队列的属性;

– IPC_SET:设置指定的消息队列的属性。

四、使用示例

下面是一个简单的使用消息队列的示例程序:

“`

#include

#include

#include

#include

#include

#include

#include

struct msgbuf {

long mtype;

char mtext[1024];

};

int mn() {

int msgid;

key_t key;

struct msgbuf buf;

// 创建一个新的消息队列,并获取其标识符

key = ftok(“.”, ‘a’);

msgid = msgget(key, IPC_CREAT | 0666);

if (msgid == -1) {

printf(“msgget error: %s\n”, strerror(errno));

exit(1);

}

// 添加三个消息

buf.mtype = 1;

strcpy(buf.mtext, “message 1”);

if (msgsnd(msgid, &buf, strlen(buf.mtext), 0) == -1) {

printf(“msgsnd error: %s\n”, strerror(errno));

exit(1);

}

buf.mtype = 2;

strcpy(buf.mtext, “message 2”);

if (msgsnd(msgid, &buf, strlen(buf.mtext), 0) == -1) {

printf(“msgsnd error: %s\n”, strerror(errno));

exit(1);

}

buf.mtype = 1;

strcpy(buf.mtext, “message 3”);

if (msgsnd(msgid, &buf, strlen(buf.mtext), 0) == -1) {

printf(“msgsnd error: %s\n”, strerror(errno));

exit(1);

}

// 读取消息队列中的消息

while(1) {

if (msgrcv(msgid, &buf, 1024, 0, IPC_NOWT) != -1) {

printf(“recvd msg: %s\n”, buf.mtext);

} else {

if (errno != ENOMSG) {

printf(“msgrcv error: %s\n”, strerror(errno));

}

break;

}

}

// 删除消息队列

if (msgctl(msgid, IPC_RMID, NULL) == -1) {

printf(“msgctl error: %s\n”, strerror(errno));

exit(1);

}

return 0;

}

“`

该程序使用 ftok 函数生成一个新的键值,并调用 msgget 函数创建一个新的消息队列,然后使用 msgsnd 函数向消息队列中添加三个消息,消息类型分别为 1、2 和 1。接着使用 msgrcv 函数从消息队列中读取所有的消息,并输出到标准输出的终端上。最后使用 msgctl 函数删除该消息队列。

五、


数据运维技术 » Linux 下的 msg.h 头文件详解 (msg.h linux)