ipc
ipc 意思就是 进程间通信机制的简称
在linux(centos)环境下 使用 ipcs
(信息查看),ipcrm
(删除), ipcmk
(创建)
通过指令 ipcs
查看, linux 支持的IPC机制有三种
- Message Queues: 消息队列
- Shared Memory Segments: 共享内存段
- Semaphore Arrays: 信号量数组
[root@process_comm#] ipcs
------ Message Queues --------
key msqid owner perms used-bytes messages
0x4201032a 0 root 666 184 2
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
------ Semaphore Arrays --------
key semid owner perms nsems
消息队列
代码示例
代码如下: 使用 gcc -o recv ipc_que_recv.c
, gcc -o send ipc_que_send.c
编译各自代码得到 recv
和 send
,分别运行
ipc_que_recv.c
#include <stdio.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
int create_msg_queue() {
/**
* 该方法通过指定参数, 生成对应的 唯一key id标识
* extern key_t ftok (const char *__pathname, int __proj_id) __THROW;
* __pathname: 存在的路径名或者文件,必须存在,否则返回错误
* __proj_id: 自己约定, 在unix中取值 1~255
*/
key_t _key = ftok("temp113", 66);
if(_key < 0) {
printf("error to ftok \n");
return;
}
printf("ftok _key: 0x%0x \n", _key);
/**
* 该方法主要是为了根据 __key 查询消息队列是否已经创建
* extern int msgget (key_t __key, int __msgflg) __THROW;
* __key: 消息队列的对象的关键字(key)
* __msgflg: 对条件进行判断
* 0666: 第一位表示 条件判断的处理方法
* 第二位表示 当前用户的权限, 读.写.可执行
* 第三位表示 group用户组权限
* 第四位表示 其它用户的权限
* ret: -1 失败, 权限被拒绝
* 0 成功
* 详见: rttno-base.h
* /proc/sys/kernel/msgmax 一个消息的字节大小
* /proc/sys/kernel/msgmnb 存放消息队列的总字节数
* /proc/sys/kernel/msgmni 系统的消息队列数目
* 查看系统支持消息队列数量,
*/
// int msgid = msgget(_key, IPC_CREAT | IPC_EXCL | 0666);
int msgid = msgget(_key, IPC_CREAT | 0666);
if(msgid < 0)
{
printf("error msgid %d \n", msgid);
// errno 是记录系统的最后一次错误代码
printf("%d : %s\n", errno, strerror(errno));
return 1;
}
printf("msgget msgid: 0x%0x \n", msgid);
return msgid;
}
struct msgbuf
{
long mtype;
unsigned char buff[92];
};
int main(int argc, char const *argv[])
{
int msg_id = create_msg_queue();
struct msgbuf sbuf;
sbuf.mtype = 0x01;
int cnt = 0;
while(1) {
cnt ++;
memset(sbuf.buff, 0x0, sizeof(sbuf.buff));
/**
* 该函数为接收队列消息
* extern ssize_t msgrcv (int __msqid, void *__msgp, size_t __msgsz, long int __msgtyp, int __msgflg);
* __msqid: msg_id
* __msgp: 接收数据的缓冲区
* __msgsz: 接收数据缓冲区的大小
* __msgtyp: 接收数据的类型, 就是可以通过三四个以上的进程之间的通信,用类型表示要发送给指定的消费者
* 0, 函数不做类型检查返回队列中最旧的内容
* >0, 接收类型等于 __msgtyp 的第一个消息
* <0, 接收类型等于或者小于msgtyp绝对值的第一个消息
* __msgflg: 控制函数行为
* IPC_NOWAIT: 队列为空,返回 ENOMSG( No message of desired type), 并将控制权交回调用函数的进程, 如果不指定, 那函数将一直处于阻塞状态
* MSG_NOERROR: 如何函数取得的消息长度大于 __msgsz, 将只返回 msgsz长度的信息, 剩下的会被丢弃, 如果不指定这个函数, 将被返回状态码E2BIG(Argument list too long)
* IPC_EXCEPT: 与msgtype配合使用返回队列中第一个类型不为msgtype的消息
* ret: -1, 读取错误, 错误存在 error 中
* 否则返回实际读取的数据长度
*/
int rlen = msgrcv(msg_id, &sbuf, sizeof(sbuf.buff), 0x02, 0);
if(rlen < 0) {
printf("%d : %s", errno, strerror(errno));
return -1;
} else {
printf("[%d]%d:%0x %0x %0x %0x\n", cnt, rlen, sbuf.buff[0],sbuf.buff[20],sbuf.buff[90],sbuf.buff[91]);
}
usleep(1000*100);
}
return 0;
}
ipc_que_send.c
#include <stdio.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
int get_msg_queue() {
key_t _key = ftok("temp113", 66);
if(_key < 0)
{
printf("%d : %s",errno,strerror(errno));
return -1;
}
int msg_id = msgget(_key, IPC_CREAT);
printf("msgid: %d \n", msg_id);
return msg_id;
}
struct msgbuf
{
long mtype;
unsigned char buff[92];
};
int main(int argc, char const *argv[])
{
int msg_id = get_msg_queue();
struct msgbuf sbuf;
memset(sbuf.buff, 'c', sizeof(sbuf.buff));
unsigned char cnt = 0;
sbuf.mtype = 0x02;
sbuf.buff[0] = 0x0;
sbuf.buff[91] = 'a';
while (1)
{
sbuf.buff[0] = cnt;
cnt++;
/**
* 该函数为向队列发送数据
* extern int msgsnd (int __msqid, const void *__msgp, size_t __msgsz, int __msgflg);
* __msgflg: 控制发送函数的行为, IPC_NOWAIT,如果消息队列已满,消息将不被写入队列,控制权返回调用函数的线程。如果不指定这个参数,线程将被阻塞直到消息被可以被写入。
* ret: 0 成功
* -1 errno
*/
int res = msgsnd(msg_id, &sbuf, sizeof(sbuf.buff), 0);
printf("[%d] res %d, rlen %d res: %0x %0x %0x %0x \n", cnt, res, sizeof(sbuf.buff),sbuf.buff[0], sbuf.buff[20], sbuf.buff[60], sbuf.buff[91]);
sleep(1);
}
return 0;
}
实验探索结论
1.当消息队列一旦创建之后, 他是存在于内核系统的, 不限于用户态的程序, 也就是说用户态的程序不管是java还是c, 不管是运行还是不运行, 不管是两个进程还是更多的进程, 他都可以对消息队列进行收发数据的操作, 异或同一进程自发自收
2.消息队列在内核中的源码