目录
system V IPC对象是内核中实际存在的对象,用于进程间通信
可以通过shell命令来管理这些对象:
一、查看ipc对象:
yutou@ubuntu:~/2206/process/homework/day03_hw$ ipcs
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
------------ 共享内存段 --------------
键 shmid 拥有者 权限 字节 连接数 状态
0x00000000 6 farsight 600 67108864 2 目标
0x00000000 11 farsight 600 524288 2 目标
0x00000000 12 farsight 600 524288 2 目标
0x00000000 13 farsight 600 524288 2 目标
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
分别查看不同类型的ipc对象
yutou@ubuntu:~/2206/process/homework/day03_hw$ ipcs -q //只查看消息队列
--------- 消息队列 -----------
键 msqid 拥有者 权限 已用字节数 消息
yutou@ubuntu:~/2206/process/homework/day03_hw$ ipcs -m //只查看共享内存
------------ 共享内存段 --------------
键 shmid 拥有者 权限 字节 连接数 状态
0x00000000 6 farsight 600 67108864 2 目标
0x00000000 11 farsight 600 524288 2 目标
0x00000000 12 farsight 600 524288 2 目标
0x00000000 13 farsight 600 524288 2 目标
yutou@ubuntu:~/2206/process/homework/day03_hw$ ipcs -s //只查看信号量
--------- 信号量数组 -----------
键 semid 拥有者 权限 nsems
删除ipc对象:
ipcrm -q id
ipcrm -m id
ipcrm -s id
这些systemV IPC对象操作思路是一致的,如下:
获取key 打开或获取ipc对象
ftok()-->key | ---> msgget() | msgrcv() ,msgsnd() msgctl()
IPC_PRIVATE-->key | ---> shmget() | shmat() , shmdt() shmctl()
---> semget() | semop(), semctl()
二、消息队列的概念
消息队列是IPC对象的一种
消息队列由消息队列ID来唯一标识
消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等。
消息队列可以按照类型来发送/接收消息
三、消息队列相关函数
1、获得key值
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
//参数1 --- 工程目录
//参数2 --- 项目编号
//返回值 ----成功:key,失败:-1
2、获取或创建消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h> int msgget(key_t key, int msgflg);
//参数1 ----- key: 通过ftok()获取,或 IPC_PRIVATE:由系统分配
//参数2 ----- 权限: IPC_CREAT | 0666
//返回值 ---- 成功:消息队列的ID ,失败:-1
例如:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define perr(str) ({perror(str);exit(1);})
int main(void)
{
key_t key;
int msg_id;
//先获取key
if((key=ftok("./",0xa)) < 0)
perr("ftok");
//创建或获取消息队列的ID
if((msg_id = msgget(key,IPC_CREAT|0666)) < 0)
perr("msgget");
return 0;
}
3、发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//参数1 ---- 消息队列ID
//参数2 ---- 结构体指针,类型为:struct msgbuf* ,该结构体需要自定义,如下:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
//参数3 ---- 表示消息正文的大小,也就是mtext的中数据的长度
//参数4 ----- 标签:0 ---如果不能立即发送,则阻塞,IPC_NOWAIT---如果不能立即发送则直接返回
//返回值 ---- 成功:0,失败:-1
4、接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
//参数1 ----- 消息队列ID
//参数2 ----- 结构体指针,类型为:struct msgbuf* ,该结构体需要自定义,如下:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
//参数3 ---- 表示消息正文的大小,也就是mtext的长度
//参数4 ---- msgtyp:
msgtyp > 0 ----要接收的消息的类型
msgtyp = 0 ----按消息的顺序接收不同类型消息
msgtyp < 0 ----接收消息类型不大于msgtyp绝对值的最小的消息
//参数5 ---- 标签:0 ---如果不能立即接收,则阻塞,IPC_NOWAIT---如果不能立即接收则直接返回
//返回值 ---- 成功:接收到的字节数,失败:-1
例如:
#include "msg.h"
int main(void)
{
key_t key;
int msg_id;
struct msgbuf buf;
//先获取key
if((key=ftok("./",0xa)) < 0)
perr("ftok");
//创建或获取消息队列的ID
if((msg_id = msgget(key,IPC_CREAT|0666)) < 0)
perror("msgget");
//向消息队列中发送消息
while(1){
memset(&buf,0,sizeof(buf));
printf("请输入消息类型:");
scanf("%ld",&buf.mtype);
while(getchar() != '\n');
printf("请输入消息:");
fgets(buf.mtext,SIZE,stdin);
buf.mtext[strlen(buf.mtext)-1] = '\0';
if(msgsnd(msg_id,&buf,strlen(buf.mtext),0) <0)
perr("msgsnd");
}
return 0;
}
#include "msg.h"
int main(void)
{
key_t key;
int msg_id;
struct msgbuf buf;
//先获取key
if((key=ftok("./",0xa)) < 0)
perr("ftok");
//创建或获取消息队列的ID
if((msg_id = msgget(key,IPC_CREAT|0666)) < 0)
perr("msgget");
//向消息队列中发送消息
while(1){
memset(&buf,0,sizeof(buf));
printf("请输入消息类型:");
scanf("%ld",&buf.mtype);
if(msgrcv(msg_id,&buf,SIZE,buf.mtype,0) <0)
perr("msgrcv");
printf("%s\n",buf.mtext);
}
return 0;
}
5、获取或设置消息队列对象的信息
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//参数1 ----- 消息队列ID
//参数2 ----- 命令:
IPC_STAT -----获取消息队列的属性,通过参数三返回
IPC_SET ----- 设置消息队列的属性
IPC_RMID ----- 删除消息队列
//参数3 ----- 结构体struct msqid_ds的指针
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 last change */
unsigned long __msg_cbytes; /* Current number of bytes in
queue (nonstandard) */
msgqnum_t msg_qnum; /* Current number of messages
in queue */
msglen_t msg_qbytes; /* Maximum number of bytes
allowed in queue */
pid_t msg_lspid; /* PID of last msgsnd(2) */
pid_t msg_lrpid; /* PID of last msgrcv(2) */
};
例如:
int main(int argc,char **argv)
{
int msg_id;
if(argc != 2){
fprintf(stderr,"Usage: %s <msgid>\n",argv[0]);
exit(1);
}
msg_id = atoi(argv[1]);
if(msgctl(msg_id,IPC_RMID,NULL) < 0)
perr("msgctl");
return 0;
}