如何使用 ftok 函数生成消息队列、共享内存或信号量所需的唯一标识符(键值)
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
int main()
{
//声明两个 key_t 类型的变量 key1 和 key2。key_t 是一个整数类型,用于表示键值。
key_t key1,key2;
//ftok 函数用于根据文件路径和项目标识符生成一个唯一的键值。
//ftok(".", 10) 和 ftok(".", 20) 分别生成了两个不同的键值,
//"." 表示当前目录,10 和 20 是项目标识符,保证生成不同的键值。
key1 = ftok(".",10);
key2 = ftok(".",20);
printf("key1 = %d\n",key1);
printf("key2 = %d\n",key2);
}
ftok
函数详解:
ftok
函数的作用是根据给定的文件路径和项目标识符生成一个唯一的 key_t
值,这个键值在创建消息队列、共享内存、信号量时作为标识符。该键值确保在同一系统中,不同的程序能够通过该键值来识别同一个资源。
key_t ftok(const char *pathname, int proj_id);
pathname
:指定用于生成key_t
的文件路径。一般来说,我们可以选择现有的文件路径。为了避免影响文件系统,通常选择当前目录"."
或某个特定的路径。proj_id
:一个项目标识符,用于区分不同的资源。它通常是一个整数值(如10
和20
)。即使文件路径相同,只要proj_id
不同,ftok
生成的键值也会不同。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
int main()
{
key_t key1,key2;
int msgid1,msgid2;
//1. 申请消息队列的key值
key1 = ftok(".",10);
key2 = ftok(".",20);
printf("key1 = %d\n",key1);
printf("key2 = %d\n",key2);
//2. 根据key值申请ID号
msgid1 = msgget(key1,IPC_CREAT|0666);
printf("msgid1 = %d\n",msgid1);
msgid2 = msgget(key2,IPC_CREAT|0666);
printf("msgid2 = %d\n",msgid2);
return 0;
}
-
msgid1 = msgget(key1, IPC_CREAT | 0666);
msgget
函数用于获取或创建一个消息队列。如果消息队列已经存在,它会返回一个消息队列的 ID。如果消息队列不存在,它会根据key1
创建一个新的消息队列。IPC_CREAT
是一个标志,表示如果消息队列不存在,则创建一个新的消息队列。0666
是权限位,表示消息队列的访问权限。0666
表示所有用户均可读写消息队列。msgid1
保存创建或获取的消息队列 ID。msgid2 = msgget(key2, IPC_CREAT | 0666);
- 同上,根据
key2
创建或获取第二个消息队列,msgid2
保存第二个消息队列的 ID。
-
msgget
:该函数用于创建或访问一个消息队列,返回一个消息队列的标识符(ID)。int msgget(key_t key, int msgflg);
key
:消息队列的键值(由ftok
函数生成)。msgflg
:控制消息队列创建或访问的标志,常用标志包括:IPC_CREAT
:如果消息队列不存在,则创建一个新的消息队列。IPC_EXCL
:和IPC_CREAT
一起使用,表示如果消息队列已存在则返回错误。0666
:指定消息队列的访问权限。
利用消息队列 (msgget
, msgsnd
, msgrcv
, msgctl
) 实现进程间通信(IPC)的基本操作
发送消息程序 (msgsend.c
)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// 定义消息的结构体
struct msgbuf {
long mtype; // 消息类型(必须为正整数)
char mtext[50]; // 消息内容
};
int main() {
key_t key;
int msgid, ret;
// 0. 定义消息变量,并赋值
struct msgbuf buf;
buf.mtype = 10; // 设置消息类型为10
bzero(&(buf.mtext), 50); // 清空消息内容
strcpy(buf.mtext, "hello"); // 设置消息内容为 "hello"
// 1. 获取消息队列的 key 值
key = ftok(".", 10); // 使用当前目录和项目标识符10生成key
printf("key = %d\n", key);
// 2. 根据 key 值获取消息队列的 ID
msgid = msgget(key, IPC_CREAT | 0666); // 创建消息队列并设置权限
printf("msgid : %d\n", msgid);
// 3. 将数据发送到消息队列中
ret = msgsnd(msgid, &buf, strlen(buf.mtext), 0); // 发送消息
if (ret == -1) {
printf("msgsnd error!\n");
exit(1);
}
return 0;
}
msgsnd(msgid, &buf, strlen(buf.mtext), 0)
: 向消息队列发送一条消息,mtype
是消息类型,mtext
是消息内容。strlen(buf.mtext)
用于传递消息内容的长度。
接收消息程序 (msgrcv.c
)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// 定义消息的结构体
struct msgbuf {
long mtype; // 消息类型(必须为正整数)
char mtext[50]; // 消息内容
};
int main() {
key_t key;
int msgid;
int ret;
struct msgbuf buf;
bzero(&(buf.mtext), 50);
// 1. 获取消息队列的 key 值
key = ftok(".", 10); // 使用当前目录和项目标识符10生成key
printf("key = %d\n", key);
// 2. 根据 key 值获取消息队列的 ID
msgid = msgget(key, IPC_CREAT | 0666); // 获取消息队列ID
printf("msgid : %d\n", msgid);
// 3. 从消息队列接收数据
ret = msgrcv(msgid, &buf, sizeof(buf.mtext), 10, 0); // 接收指定类型的消息
if (ret < 0) {
printf("msgrcv error!\n");
}
// 打印接收到的消息内容
printf("buf.mtext = %s\n", buf.mtext);
// 4. 删除消息队列
msgctl(msgid, IPC_RMID, NULL); // 删除消息队列
return 0;
}
msgrcv(msgid, &buf, sizeof(buf.mtext), 10, 0)
: 从消息队列接收消息,指定接收类型为10
,并将接收到的消息存储在buf.mtext
中。sizeof(buf.mtext)
表示接收消息的最大长度。msgrcv
会阻塞等待消息,直到接收到指定类型的消息。msgctl(msgid, IPC_RMID, NULL)
: 删除消息队列。
关键点总结:
-
消息队列的创建与访问:
- 通过
ftok()
获取一个唯一的键值(key
)。 - 通过
msgget()
使用key
获取或创建消息队列。
- 通过
-
发送消息:
- 使用
msgsnd()
将消息发送到消息队列。消息由mtype
(类型)和mtext
(内容)组成。
- 使用
-
接收消息:
- 使用
msgrcv()
从消息队列中接收消息,消息根据mtype
被选取。
- 使用
-
删除消息队列:
- 使用
msgctl()
删除消息队列。
- 使用
注意事项:
- 消息队列通过
mtype
字段区分消息类型,这样接收方可以根据需要接收特定类型的消息。 msgsnd()
和msgrcv()
都会返回-1
表示出错,需检查返回值进行错误处理。msgctl()
中的IPC_RMID
用来删除消息队列,但通常在使用完消息队列之后执行。
这样,父子进程之间可以通过消息队列实现数据传输。