1、IPC对象
除了最原始的进程间通信方式信号、无名管道和有名管道外,还有三种进程间通信方式,这
三种方式称之为IPC对象
IPC对象分类:消息队列、共享内存、信号量(信号灯集)
IPC对象也是在内核空间开辟区域,每一种IPC对象创建好之后都会将其设置为全局,并且
会给其分配一个编号,只要找到唯一的这个编号就可以进行通信,所以不相关的进程可以通
过IPC对象通信。
IPC对象创建好之后,会在当前系统中可见,只要不删除或者不关闭系统,就会一直存在。
查看已经创建的IPC对象:
ipcs 查看当前系统中所有创建的 IPC 对象ipcs ‐q 查看创建的消息队列ipcs ‐m 查看创建的共享内存ipcs ‐s 查看信号量ipcrm 删除 IPC 对象例如: ipcrm ‐q msqid 删除标号为 msqid 的消息队列
2、消息队列的概述
2.1 消息队列的概念
消息队列是消息的链表,存放在内存中,由内核维护
消息队列的特点
1、消息队列中的消息是有类型的。
2、消息队列中的消息是有格式的。
3、消息队列可以实现消息的随机查询。消息不一定要以先进先出的次序读取,编程时可以
按消息的类型读取
4、消息队列允许一个或多个进程向它写入或者读取消息。
5、与无名管道、命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删
除。
6、每个消息队列都有消息队列标识符,消息队列的标识符在整个系统中是唯一的。
7、只有内核重启或人工删除消息队列时,该消息队列才会被删除。若不人工删除消息队
列,消息队列会一直存在于系统中。
在ubuntu 12.04中消息队列限制值如下:
每个消息内容最多为8K字节
每个消息队列容量最多为16K字节
系统中消息队列个数最多为1609个
系统中消息个数最多为16384个
System V提供的IPC通信机制 需要一个key值, 通过key值就可在系统内获得一个唯一的消
息队列标识符 。
key值可以是人为指定的,也可以通过ftok函数获得。
如果多个进程想通过IPC对象通信,则必须找到唯一的标识,而唯一的标识是由key决定
的,所以只要key知道,则就可以实现多个进程通信
(另外,Posix IPC的操作稍有不同,后面补充)
2.2 ftok函数
ftok - convert a pathname and a project identifier to a System V IPC key
#include <sys/types.h>#include <sys/ipc.h>key_t ftok ( const char *pathname, int proj_id );功能:通过文件名和目标值共同创造一个键值并返回值参数:pathname :任意一个文件名(文件名或者目录名)proj_id:目标值,范围一般是 0~127返回值:成功:键值失败: ‐1如果使用 ftok 函数获取键值,得到的键值是由 ftok 的第一个 参数对应文件的信息和第二个参数一起决定的
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>int main(int argc, char const *argv[])
{//使用ftok函数获取键值//只要保证ftok的第一个参数对应的文件和第二个参数值相同,则不管程序运行多少遍或者多少个进程或者键值//键值一定都是唯一的key_t mykey;mykey = ftok("test",666);if(mykey==-1){perror("fail to ftok");exit(1);}
printf("mykey = %#x\n", mykey);return 0;
}
3、消息队列操作
3.1创建消息队列 -- msgget()
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget ( key_t key, int msgflg );功能:创建一个消息队列,得到消息队列的 id参数:key :键值,唯一的键值确定唯一的消息队列方法 1 :任意指定一个数方法 2 :使用 ftok 函数获取键值msgflg :消息队列的访问权限,一般设置为 IPC_CREAT | IPC_EXCL | 0777 或者 IPC_CREAT | 0777返回值:成功:消息队列的 id失败:‐1
查看消息队列ipcs ‐q删除消息队列ipcrm ‐q msqid
测试msgget
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/msg.h>int main(int argc, char const *argv[])
{key_t mykey;mykey = ftok("test", 666);if (mykey == -1){perror("fail to ftok");exit(1);}printf("mykey = %#x\n", mykey);// 通过msgget函数创建一个消息队列int msgid;msgid = msgget(mykey, IPC_CREAT | 0666);if (msgid == -1){perror("fail to msgget");exit(1);}printf("msgid = %d\n", msgid);system("ipcs -q");return 0;
}
3.2 发送消息-- 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 :消息队列的idmsgp :要写入的数据,需要自己定义结构体struct struct_name {long mtype ; // 消息的编号,必须大于 0char mtext [ 128 ]; // 消息正文,可以定义多个成员...}msgsz :消息正文的大小,不包括消息的编号长度msgflg :标志位0 阻塞IPC_NOWAIT 非阻塞返回值:成功: 0失败: ‐ 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>#define N 128typedef struct
{long msg_type; //消息类型,必须在结构体的第一个位置并且类型必须是longchar msg_text[N]; //消息正文,也可以有多个成员并且类型也可以是任意
}MSG ;#define MSG_SIZE (sizeof(MSG)-sizeof(long))
int main(int argc, char const *argv[])
{key_t mykey;mykey = ftok("test", 666);if (mykey == -1){perror("fail to ftok");exit(1);}printf("mykey = %#x\n", mykey);// 通过msgget函数创建一个消息队列int msgid;msgid = msgget(mykey, IPC_CREAT | 0666);if (msgid == -1){perror("fail to msgget");exit(1);}//printf("msgid = %d\n", msgid);system("ipcs -q");MSG msg1 ={1,"hello world"};
MSG msg2 ={3,"UCC"};MSG msg3 ={2,"giant"};MSG msg4 ={4,"美利达"};if(msgsnd(msgid,&msg1,MSG_SIZE,0)==-1){perror("fail to send");exit(1);
}if(msgsnd(msgid,&msg2,MSG_SIZE,0)==-1){perror("fail to send");exit(1);
}
if(msgsnd(msgid,&msg3,MSG_SIZE,0)==-1){perror("fail to send");exit(1);
}
if(msgsnd(msgid,&msg4,MSG_SIZE,0)==-1){perror("fail to send");exit(1);
}system("ipcs -q");return 0;
}
3.3 消息接收--msgrcv()
# include <sys/ipc.h># include <sys/msg.h>ssize_t msgrcv ( int msqid , void * msgp , size_t msgsz ,long msgtyp , int msgflg );功能:从消息队列中接收数据(读操作),接收的数据会从消息队列中删除参数:msqid :消息队列idmsgp :保存接收到的数据的结构体struct struct_name {long mtype ; // 消息的编号,必须大于 0char mtext [ 128 ]; // 消息正文,可以定义多个成员}msgsz :消息正文的大小msgtyp :设置要接收哪个消息0 按照写入消息队列的顺序依次读取> 0 只读取消息队列中消息编号为当前参数的第一个消息< 0 只读取消息队列中小于等于当前参数的绝对中内最小的第一个消息msgflg :标志位0 阻塞IPC_NOWAIT 非阻塞返回值:成功:接收到的消息正文的长度失败: ‐ 1
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/msg.h>#define N 128
typedef struct
{long msg_type; //消息类型,必须在结构体的第一个位置并且类型必须是longchar msg_text[N]; //消息正文,也可以有多个成员并且类型也可以是任意
}MSG ;#define MSG_SIZE (sizeof(MSG)-sizeof(long))int main(int argc, char const *argv[])
{key_t mykey;mykey = ftok("test", 666);if (mykey == -1){perror("fail to ftok");exit(1);}printf("mykey = %#x\n", mykey);// 通过msgget函数创建一个消息队列int msgid;msgid = msgget(mykey, IPC_CREAT | 0666);if (msgid == -1){perror("fail to msgget");exit(1);}//printf("msgid = %d\n", msgid);system("ipcs -q");//通过msgrcv函数接收消息队列中的信息(读操作)
//注意:如果没有第四个参数指定的消息时,msgrcv函数会阻塞等待
MSG msg;
//如果第四个参数为0,则按照先进先出的方式读取数据//if(msgrcv(msgid,&msg,MSG_SIZE,0,0))//如果第四个参数为>0,则获取当前值得消息类型的数据
//if(msgrcv(msgid, &msg, MSGTEXT_SIZE, 2, 0) == ‐1)//如果第四个参数为<0,则获取当前值得绝对值内消息类型最小的数据if(msgrcv(msgid, &msg, MSG_SIZE, -3, 0) == -1){perror("fail to msgrcv");exit(1);}printf("recv_msg = %s\n", msg.msg_text);system("ipcs -q");return 0;
}