System V IPC的概念
System V IPC(System V Interprocess Communication)是Unix和类Unix操作系统中一套传统的进程间通信机制,它包括三种主要的通信方式:消息队列、信号量和共享内存。这些机制提供了一种在不同进程之间交换数据和同步操作的手段。
System V IPC 是由内核维护的若干个对象,在Linux系统下可以通过 ipcs 命令查询
ftok()
函数用于生成一个IPC(进程间通信)对象(如消息队列、信号量或共享内存)的唯一标识符(key)。这个key用于后续的IPC操作,如创建或访问这些IPC资源。
ftok()函数
函数描述:
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
函数原型
key_t ftok(const char *pathname, int proj_id);
函数参数
pathname:指向一个存在的文件的路径。ftok()会使用该文件的inode号来帮助生成 key。这个文件不必与IPC通信有任何直接关系,但它必须存在于文件系统中。
proj_id:是一个用户定义的值,用于进一步确保key的唯一性。这是一个非负整数,但通常是一个小于 256 的正整数。
函数返回值
成功 返回一个key_t类型的值。
错误 返回-1,并设置errno以指示错误原因。
示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
int main() {
key_t key;
const char *path = "/etc/passwd"; // 一个存在的文件
int proj_id = 123; // 标识符
key = ftok(path, proj_id);
if (key == -1) {
perror("ftok error");
exit(1);
}
printf("The key value is %d\n", key);
return 0;
}
消息队列
消息队列简介
在Linux系统中,消息队列是一种进程间通信(IPC)机制,允许不同进程向队列中添加消息,其他进程可以从队列中读取消息。消息队列可以跨多个进程共享,支持多种数据类型,并且可以设置消息优先级。
消息队列具有FIFO的特性,具有无名管道与有名管道各自的优势,可以支持任意两个进程的进程间通讯
消息队列的操作步骤:
创建消息队列:
使用msgget()
函数创建一个新的消息队列或访问一个现有的消息队列。
msgget()函数
函数描述:
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型
int msgget(key_t key, int msgflg);
函数功能
获取System V消息队列标识符
函数参数
key:由ftok函数合成
msgflg:消息队列标志 I
PC_CREAT 创建标志
IPC_EXCL 如果消息队列存在,则报错, errno设置为EEXIST
权限控制标志
函数返回值
成功:返回消息队列id
失败:返回-1,并设置errno
发送消息:
使用msgsnd()
函数将消息发送到消息队列。
函数描述:
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);
函数参数:
msqid:消息队列ID
msgp:消息结构体指针
msgsz:消息内容的长度
msgflg:消息队列标志,默认可以填0,IPC_NOWAIT,可以设置非阻塞
函数返回值
成功:返回0
失败:-1,并设置errno
接收消息:
使用msgrcv()
函数从消息队列中接收消息。
msgrcv()函数
函数描述:
函数头文件
#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:消息队列id
msgp:消息结构指针
msgsz:最大读取的字节数
msgtyp:消息类型
msgflg:消息队列标志,默认可以填0,IPC_NOWAIT,可以设置非阻塞
函数返回值
成功:返回实际读取消息内容的字节数
失败:-1,并设置 errno
删除消息队列:
使用msgctl()
函数删除消息队列
msgctl()函数
msgctl()对标识符为msqid的System V消息队列执行cmd指定的控制操作
函数头文件
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数参数
msqid:消息队列id
cmd:命令字
IPC_STAT:获取消息队列属性
IPC_SET:设置消息队列属性
IPC_RMID:删除消息队列,用此命名时,第三个参数为NULL
buf:消息队列属性结构体对象指针
函数返回值
成功:IPC_STAT, IPC_SET, and IPC_RMID 返回0
失败:返回-1,并设置 errno
消息队列属性结构体定义
struct ipc_perm {
key_t __key; /* Key supplied to msgget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */
unsigned short __seq; /* Sequence number */
};
struct msqid_ds {
struct ipc_perm msg_perm; /* Ownership and permissions */
time_t msg_stime; /* Time of last msgsnd(2) */
time_t msg_rtime; /* Time of last msgrcv(2) */
time_t msg_ctime; /* Time of creation or last
modification by msgctl() */
unsigned long msg_cbytes; /* # of bytes in queue */
msgqnum_t msg_qnum; /* # number of messages in queue */
msglen_t msg_qbytes; /* Maximum # of bytes in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
总结:
消息队列整体代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <unistd.h>
// 定义消息结构体
struct my_msg {
long mtype; // 消息类型,必须大于0
char mtext[100]; // 消息数据
};
int main() {
int msqid;
struct my_msg msg;
// 创建消息队列
msqid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
if (msqid == -1) {
perror("msgget");
exit(1);
}
// 向消息队列发送消息
msg.mtype = 1;
strcpy(msg.mtext, "Hello, World!");
if (msgsnd(msqid, &msg, sizeof(msg.mtext), 0) == -1) {
perror("msgsnd");
exit(1);
}
// 从消息队列接收消息
if (msgrcv(msqid, &msg, sizeof(msg.mtext), 1, 0) == -1) {
perror("msgrcv");
exit(1);
}
printf("Received: %s\n", msg.mtext);
// 删除消息队列
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
return 0;
}
代码解读:
- 定义了一个结构体
my_msg
,用于存储消息队列中的消息。 mtype
是消息的类型,它必须是一个大于0的长整型数,用于区分不同的消息类型。mtext
是消息的数据部分,这里定义为一个100字符的数组- 定义了一个消息队列标识符
msqid
和一个消息结构体变量msg
。 - 使用
msgget
函数创建一个消息队列,IPC_PRIVATE
作为键值参数表示创建一个只对当前进程可见的私有消息队列。0666 | IPC_CREAT
设置了消息队列的权限,并指示如果队列不存在则创建它。 - 如果创建失败,使用
perror
打印错误信息并退出 - 设置消息的类型为1,并设置消息文本为"Hello, World!"。
- 使用
msgsnd
函数向消息队列发送消息。msgsnd
的第四个参数0
表示消息按类型排序。 - 如果发送失败,使用
perror
打印错误信息并退出。 - 使用
msgrcv
函数从消息队列接收类型为1的消息。sizeof(msg.mtext)
指定了消息数据的最大长度。 - 如果接收失败,使用
perror
打印错误信息并退出 - 打印接收到的消息。
- 使用
msgctl
函数删除消息队列,IPC_RMID
是控制命令,指示删除消息队列。 - 如果删除失败,使用
perror
打印错误信息并退出。
结语:
无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力