一、IPC进程间通信相关命令
ipcs:查看当前系统中已经使用的IPC进程间通信(1.2.3)
ipcs -q:单独查看消息队列
ipcs -m: 单独查看共享内存
ipcs -s:单独查看信号灯集
ipcrm:删除IPC进程间通信
ipcrm -q msqid 删除消息队列号为msqid的消息队列
ipcrm -m shmid 删除共享内存号为shmid的共享内存
ipcrm -s semid 删除信号灯集号为semid的信号灯集
二、键值
ftok函数原理解析
#include <sys/types.h>
#include <sys/ipc.h>
函数原型:
key_t ftok(const char *pathname, int proj_id);
参数:
pathname:已经存在的文件路径以及名字
proj_id:任意一个字符或者数字,它的低八位有效 1 'a'
返回值:
成功返回获取的key键值, 失败返回-1
使用:若两个进程间需要建立通信,需要使用相同的键值。即两个参数相同。
三、消息队列
- 消息队列也是借助内核实现,A进程将消息放入消息队列中,队列中的消息是一个结构体,由两部分组成,消息的类型和消息的正文,正文可以是字符串,整型,数组,结构体。
- B进程可以根据想取的消息的类型将消息从队列中取走。消息队列的大小默认为16K(16384字节),如果消息队列中的消息满了,A进程就会写阻塞,
什么时候B进程读取一个A进程才能继续写。
![1](https://i-blog.csdnimg.cn/blog_migrate/c3f7f823ae95d13bb47ada3de3c60915.png)
四、 消息队列API(msgget / msgsnd / msgrcv / msgctl )
四个函数头文件都如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型:
int msgget(key_t key, int msgflg);
功能:创建消息队列
参数:@key:键值----通过ftok获取
IPC_PRIVATE: 只能用于亲缘进程间通信(可以这么用,但是一般不用)
@msgflg:消息队列的标志位
IPC_CREAT:创建,比如使用时候(IPC_CREAT | 0666),
如果这个时候消息队列已经存在了,会直接返回消息队列号
IPC_EXCL: 如果消息队列已经存在,就报错
返回值:成功返回消息队列号,失败返回-1置位错误码
------------------------------------------------------------------
函数原型:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:往消息队列里面发送数据
参数:
@msqid:消息队列号
@msgp:消息的首地址
struct msgbuf {
long mtype;
char mtext[1];
};
@msgsz: 消息正文的大小(不包含类型)
@msgflg:消息的标志
0 : 阻塞发送(如果写满16K 再往里面写会阻塞等,读取一个写进去一个)
IPC_NOWAIT: 非阻塞发送数据(如果写满16K 再往里面写会直接报错返回)
返回值:成功返回0,失败返回-1置位错误码
-----------------------------------------------------------------------------
函数原型:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
功能:从消息队列中获取数据
参数:
@msgqid:消息队列号
@msgp:消息的首地址
@msgsz:消息正文的大小
@msgtyp:消息的类型:
如果=0:接受消息队列中的第一个消息
如果>0:就会接收msgtyp指定的消息类型
如果<0:就会读取队列中第一最小类型小于或等于msgtyp绝对值的消息
@msgflg:消息的标志:
0 : 阻塞接受(如果消息队列中没有消息,读的时候阻塞等,写进去一个读一个)
IPC_NOWAIT: 非阻塞接收(如果消息队列中没有消息,读的时候直接报错返回)
返回值:成功返回接收到的字节个数,失败返回-1置位错误码
---------------------------------------------------------------------------
函数原型:
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:控制消息队列
参数:
@msgqid:消息队列号
@cmd: 命令
IPC_STAT: 获取消息队列的属性
IPC_SET: 设置消息队列的属性
IPC_RMID: 立即删除消息队列
@buf:消息队列属性的结构体 如果第二个参数为IPC_RMID,该参数传NULL即可
返回值:成功返回0 ,失败返回-1。
比如:msgctl(msgqid, IPC_RMID, NULL); 删除消息队列
五、示例:消息队列实现进程间通信
write.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
typedef struct {
long mtype;
char mtext[128];
}msg_t;
int main(){
key_t key;
if((key = ftok("/home/linux/2307", 'a')) == -1){
printf("ftok error\n");return -1;
}
int msqid;
if(( msqid = msgget(key, IPC_CREAT | 0666)) == -1){
printf("msgget error\n");return -1;
}
msg_t msg = {
.mtype = 20,
};
while(1){
printf("input > ");
fgets(msg.mtext, sizeof(msg.mtext), stdin);
msg.mtext[strlen(msg.mtext) - 1] = '\0';
msgsnd(msqid, &msg, strlen(msg.mtext), 0);
if(strcmp(msg.mtext, "quit") == 0)
break;
}
return 0;
}
read.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
typedef struct {
long mtype;
char mtext[128];
}msg_t;
int main(){
key_t key;
if((key = ftok("/home/linux/2307", 'a')) == -1){
printf("ftok error\n");return -1;
}
int msqid;
if(( msqid = msgget(key, IPC_CREAT | 0666)) == -1){
printf("msgget error\n");return -1;
}
msg_t msg;
while(1){
memset(&msg, 0, sizeof(msg));
msgrcv(msqid, &msg, sizeof(msg.mtext), 20, 0);
printf("type = %ld, msg = %s\n", msg.mtype, msg.mtext);
if(strcmp(msg.mtext, "quit") == 0)
break;
}
return 0;
}
write.c—2
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#define MSGSIZE (sizeof(msg_t)-sizeof(long))
typedef struct {
long type;
char name[20];
int age;
char sex;
}msg_t;
int main(){
key_t key;
if((key = ftok("/home/linux/2307", 'a')) == -1){
printf("ftok error\n");return -1;
}
int msqid;
if(( msqid = msgget(key, IPC_CREAT | 0666)) == -1){
printf("msgget error\n");return -1;
}
msg_t msg1 = {
.type = 1,
.name = "zhangsan",
.age = 18,
.sex = 'm',
};
msgsnd(msqid, &msg1, MSGSIZE, 0);
msg_t msg2 = {
.type = 2,
.name = "lisi",
.age = 20,
.sex = 'm',
};
msgsnd(msqid, &msg2, MSGSIZE, 0);
msg_t msg3 = {
.type = 3,
.name = "disange",
.age = 20,
.sex = 'w',
};
msgsnd(msqid, &msg3, MSGSIZE, 0);
msg_t msg4 = {
.type = 4,
.name = "disige",
.age = 20,
.sex = 'w',
};
msgsnd(msqid, &msg4, MSGSIZE, 0);
return 0;
}
read.c --2
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#define MSGSIZE (sizeof(msg_t)-sizeof(long))
typedef struct {
long type;
char name[20];
int age;
char sex;
}msg_t;
int main(int argc, const char *argv[]){
key_t key;
if((key = ftok("/home/linux/2307", 'a')) == -1){
printf("ftok error\n");return -1;
}
int msqid;
if(( msqid = msgget(key, IPC_CREAT | 0666)) == -1){
printf("msgget error\n");return -1;
}
msg_t msg;
memset(&msg, 0, sizeof(msg));
msgrcv(msqid, &msg, MSGSIZE, 1, 0);
printf("type = %ld, name = %s, age = %d, sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
memset(&msg, 0, sizeof(msg));
msgrcv(msqid, &msg, MSGSIZE, 2, 0);
printf("type = %ld, name = %s, age = %d, sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
memset(&msg, 0, sizeof(msg));
msgrcv(msqid, &msg, MSGSIZE, 3, 0);
printf("type = %ld, name = %s, age = %d, sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
memset(&msg, 0, sizeof(msg));
msgrcv(msqid, &msg, MSGSIZE, 4, 0);
printf("type = %ld, name = %s, age = %d, sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
return 0;
}