“我希望那个世界的自己,可以是一名旅行家,周游世界,记录世界各地的风景。”
I hope I can be a traveler, traveling around the world and recording the worldwide scenery.
System-V IPC通信机制
程序构架流程:
IPC 对象的 key
相关API
key_t ftok(const char *pathname, int proj_id);
消息队列
int msgget(key_t key, int msgflg);
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg)
什么是IPC:
消息队列、共享内存和信号量被统称为system-VIPC,V是罗马数字5,是Unix的AT&T分支的其中一个版本,一般习惯称呼他们为IPC对象,这些对象的操作接口都比较类似,在系统中他们都使用一种叫做key的键值来唯一标识,而且他们都是“持续性”资源——即他们被创建之后,不会因为进程的退出而消失,而会持续地存在,除非调用特殊的函数或者命令删除他们。
IPC里面有什么:
跟文件类型,进程每次“打开”一个IPC对象,就会获得一个表征这个对象的ID,进而再使用这个ID来操作这个对象。IPC对象的,但是ID是可变的。key类似于文件的路径名,ID类似于文件的描述符。
系统中的多个进程,如果他们需要使用IPC对象来通信,那么他们必须持有这个对象的键值key:
#include
#include
key_t ftok(const char *pathname, int proj_id);
函数功能:
函数参数:
返回值:
消息队列的使用方法一般是:
当发送者和接收者都不再使用消息队列时,及时删除它以释放系统资源。
#include
#include
#include
int msgget(key_t key, int msgflg);
函数功能:
函数参数:
返回值:
#include
#include
#include
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数功能:
函数参数:
其中这些返回的结构体有以下内容:
struct msqid_ds {
struct ipc_perm msg_perm; /* 消息队列的权限,在下面会有说明 */
time_t msg_stime; /* 发送数据的最新时间 */
time_t msg_rtime; /* 接受数据的时间 */
time_t msg_ctime; /* 最新更新时间 */
unsigned long __msg_cbytes; /* 当前队列当中的数据的字节数 */
msgqnum_t msg_qnum; /* 当前队列当中的消息数 */
msglen_t msg_qbytes; /* 在队列当中的最大的字节数 */
pid_t msg_lspid; /* 发送数据的进程的pid */
pid_t msg_lrpid; /* 接受数据的进程的pid是谁 */
};
struct ipc_perm {
key_t __key; /* IPC对象的key值 */
uid_t uid; /* 用户的ID */
gid_t gid; /* 组ID */
uid_t cuid; /* 创建的用户ID */
gid_t cgid; /* 创建的组ID */
unsigned short mode; /* 权限值*/
unsigned short __seq; /* 消息队列的下标值,也就是序列号 */
};
struct msginfo {
int msgpool; /* 系统消息总尺寸 */
int msgmap; /* 系统消息个数最大值 */
int msgmax; /* 系统单个消息尺寸最大值 */
int msgmnb; /* 吸入消息队列字节数最大值 */
int msgmni; /* 系统消息队列个数最大值 */
int msgssz; /* 消息段尺寸 */
int msgtql; /* 系统中所有消息队列中的消息总数最大值 */
unsigned short int msgseg;
/* 分配给消息队列的数据段的最大值 */
};
返回值:
#include
#include
#include
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
函数功能:
函数参数:
truct msgbuf {
/* 消息类型,必须是大于0的一个数字 */
long mtype;
/* 消息的内容,这个数组的大小是可以变化的,最大大小不能超过MAXMNB,也就是16k*/
char mtext[1];
};
返回值:
#include
#include
#include
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
函数功能:
函数参数:
返回值:
写端msg_write.c
#include
#include
#include
#include
#include
//根据消息队列的要求,定义了一个消息结构体
typedef struct{
long mtype; /* 消息类型,这个值必须大于0 */
char mtext[1024]; /* 消息数据,大小可变,最大不能超过16k */
}msgbuf_t;
int main(void)
{
key_t key;
int msg_id;
int retval;
///1、获取一个IPC对象
key = ftok(".", 1);
if(key == -1)
{
perror("获取IPC对象的key值出错");
return -1;
}
//2、获取一个消息队列,key代表操作哪个IPC对象,IPC_CREAT代表如果消息队列不存在则创建,0644代表创建出来的权限
msg_id = msgget( key, IPC_CREAT|0644);
if(msg_id == -1)
{
perror("创建或者打开消息队列出错");
return -1;
}
msgbuf_t mymsg;//用自己定义的消息结构体类型定义一个消息变量
mymsg.mtype = 250;//将消息的类型赋值为250
//3、开始操作对象
while(1)
{
//获取用户输入
fgets(mymsg.mtext,sizeof(mymsg.mtext),stdin);
/*发送消息进入指定的消息队列中
msg_id:发送的消息队列是哪个
mymsg:我们要发送的消息
strlen(mymsg.mtext):发送的消息的文本大小
0:代表正常操作消息队列
*/
retval = msgsnd( msg_id, &mymsg, strlen(mymsg.mtext), 0);
if(retval == -1)
{
perror("发送消息失败");
break;
}
}
//4、删除消息队列
msgctl( msg_id, IPC_RMID, NULL);
return 0;
}
读端msg_write.c
#include
#include
#include
#include
#include
//根据消息队列的要求,定义了一个消息结构体
typedef struct{
long mtype; /* 消息类型,这个值必须大于0 */
char mtext[1024]; /* 消息数据,大小可变,最大不能超过16k */
}msgbuf_t;
int main(void)
{
key_t key;
int msg_id;
int retval;
//获取一个IPC对象
key = ftok(".", 1);
if(key == -1)
{
perror("获取IPC对象的key值出错\n");
return -1;
}
//获取一个消息队列,key代表操作哪个IPC对象,IPC_CREAT代表如果消息队列不存在则创建,0644代表创建出来的权限
msg_id = msgget( key, IPC_CREAT|0644);
if(msg_id == -1)
{
perror("创建或者打开消息队列出错\n");
return -1;
}
msgbuf_t mymsg;//用自己定义的消息结构体类型定义一个消息变量
struct msqid_ds remsg;//定义存放消息队列的信息结构体
while(1)
{
msgctl(msg_id,IPC_STAT,&remsg);//获取消息队列的信息
printf("当前队列当中的消息数:%lu\n",remsg.msg_qnum);
printf("当前队列当中的数据的字节数 %ld\n",remsg.__msg_cbytes);
/*
发送消息进入指定的消息队列中
msg_id:接收的消息队列是哪个
mymsg:我们要接收的消息
strlen(mymsg.mtext):接收的消息的文本大小
250:对方的消息类型
0:代表正常操作消息队列
*/
retval = msgrcv( msg_id, &mymsg, sizeof(mymsg.mtext), 250, 0);
if(retval == -1)
{
perror("接受消息失败\n");
break;
}
printf("读取到消息大小为%d,内容为 %s \n", retval, mymsg.mtext);
}
//删除消息队列
msgctl( msg_id, IPC_RMID, NULL);
return 0;
}