1.System V消息队列
2.System V信号量
3.System V共享内存
这三种类型的IPC合称为System V IPC,原因是它们源自System V Unix。
IPC操作命令:
ipcs -s :查看信号量
ipcs -m :查看内存映射
ipcs -q :查看消息队列
这三种IPC机制都需要使用key_t作为它们的名字(名字空间) ,key_t一个整数类型由ftok函数创建
ftok函数把一个已经存在的路径名和一个整数标识符转换成一个key_t类型的值,称为IPC键值
函数原型:key_t ftok(const char* pathname,int id)
参数: pathname:已经存在的路径名
id:整数标识符
返回值:成功返回IPC键值 出错返回-1
功能:把从pathname导出的信息与id的低8位组合成一个整数IPC键
通过调用stat函数,然后组合下面三个值得到32位的IPC键:
1.低16位由pathname文件节点值低16位(stat结构的st_dev成员)
2.中间8位由pathname文件设备编号值低8位(stat结构的st_ino成员)
3.高8位是 int proj_id 低8位(不能为0)
查看ftok函数生成的IPC值:
# include <sys/types.h>
# include <stdio.h>
# include<stdlib.h>
# include <sys/ipc.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/msg.h>
int main(int argc, char const *argv[])
{
if(argc!=2)
perror("usage:ftork pathname!\n");
//实现
key_t key=ftok(argv[1],0x1234);
if(key==-1)
{
perror("ftok");
return;
}
struct stat st;
stat(argv[1],&st);
printf("st_dev:%lx,st_ino:%lx,key:%x\n",(long)st.st_dev,(long)st.st_ino,key);
return 0;
}
[root@localhost examp]# ./a.out file.txt
st_dev:15,st_ino:171,key:34150171
System V消息队列
消息队列以链表队列方式,实现任意两个进程之间通信,一端为读进程,另一端为写进程,依据消息ID(消息队列标识符)
值获取对应的消息(读取成功后,消息将从消息队列中释放)。在某个进程往一个队列中写入一个消息之前,不要求另外某个进程正在等待该队列上一个消息的到达。
a.消息队列特点:
1.消息队列由消息节点组成
节点类型是:
struct msgbuf
{
long mtype; /消息的类型,必须>0/
char mtext[N]; /存放消息数据/
};
2.读一个空消息队列,读进程堵塞
3.写一个已满的消息队列,写进程堵塞
4.读一个消息节点,该节点将从队列中删除
5.读进程,必须指定消息类型:
id=0:第一个消息节点
id不存在 堵塞
id存在 ,读取此节点
b.消息队列实现步骤:
1.创建ipc key 值,调用ftork函数
key_t ftok(const char* pathname,int id)
2.创建消息队列ID值,调用msgget函数:
函数原型:int msgget(key_t key,int flag)
功能:创建一个新的消息队列或者访问一个已经存在的消息队列
参数: key:ftok返回的键值 也可以是IPC_PRIVATE(保证创建唯一一个IPC对象)
flag:读写权限的组合也可以是 IPC_CREAT 或者是 IPC_CREAT|IPC_EXCL
返回值:成功返回消息队列的标识值,出错返回-1
3.消息发送,调用msgsend函数
函数原型:int msgsend(int msqid, const void * ptr,int len,int flag)
功能:放置一个消息在消息队列上
参数: msqid: msgget返回值
ptr:一个结构体指针 自定义
如: typedef struct msgbuf
{
long mtype;//消息;类型必须>0
char mtext[1024];//消息内容
}msgbuf;
len:发送消息的长度
flag: 0 堵塞
IPC_NOWAIT 非堵塞立即返回
返回值:成功返回0,出错返回-1
4.消息接收,调用msgcv函数
函数原型:size_t msgrcv(int msqid,void *ptr,size_t len,long type,int flag)
功能:从某个消息队列中读取数据
参数:msqid:msgget返回值
ptr:一个结构体指针 自定义
如:
typedef struct msgbuf
{
long mtype;//消息类型。必须>0
char mtext[1024];//消息内容
}msgbuf;
len:ptr指向缓冲区的数据部分的大小,该函数返回的最大数据量是1024
type:=0 消息队列的第一个消息
0 返回其类型值为type 的第一个消息
<0 返回其类型值小于等于type参数的消息中类型最小的第一个消息
flag: 0 堵塞
IPC_NOWAIT 非堵塞立即返回
返回值:成功返回读入缓冲区的数据的字节数 出错返回-1
6.释放消息队列 调用msgctl函数
函数原型 : int msgctl(int msgid,int cmd,struct msqid_ds* buf)
参数:msqid:msgget返回值
cmd: IPC_RMID :删除消息队列 对于该命令 第三个参数设置为NULL
IPC_SET :给所指定的消息队列设置其msqid_ds结构的以下四个成员:msg_perm.uid
msg_perm.gid,msg_perm.mode,msg_qbytes.他们来自由buf参数指向的结构中的相应成员。
IPC_STAT:(通过buf参数)给调用者返回与所指定消息队列对应的当前msqid_ds结构。
返回值:若成功返回0 出错返回-1
对于系统的消息队列信息,内核维护一个定义在下面的消息结构。
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; //最后发送进程ID
pid_t msg_lrpid; //最后接收进程ID
};
消息发送:
//文件名为IPCSEND.c
# include <sys/types.h>
# include <stdio.h>
# include<stdlib.h>
# include <sys/ipc.h>
#include <sys/msg.h>
#include <fcntl.h>
//定义消息结构
typedef struct msgbuf
{
long type;
char strbuf[10];
}msgbuf;
int main(int argc, char const *argv[])
{
key_t key=ftok(argv[1],0x57);
if(key==-1)
{
perror("ftok:\n");
return ;
}
printf("%X\n",key);
/*创建一个新的消息队列或访问一个已经存在的消息队列*/
int msgid=msgget(key,IPC_CREAT|IPC_EXCL);
if(msgid==-1)
{
perror("msgget fail");
return;
}
msgbuf buf;
buf.type=14;//消息类型
gets(buf.strbuf);
msgsnd(msgid,&buf,sizeof(buf)-sizeof(long),0);//消息发送
return 0;
}
读取/接收
//文件取名为IPCRECV.c
# include <sys/types.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/ipc.h>
#include <sys/msg.h>
#include <fcntl.h>
typedef struct msgbuf
{
long type;
char strbuf[10];
}msgbuf;
int main(int argc, char const *argv[])
{
key_t key=ftok(argv[1],0x57);
if(key==-1)
{
perror("ftok:");
exit(0);
}
printf("%X\n",key);
int msgid=msgget(key,O_RDWR);
if(msgid==-1)
{
perror("msgget:");
exit(0);
}
msgbuf buf;
int id;
scanf("%d",&id);//输入要接收的消息类型
msgrcv(msgid,&buf,sizeof(buf)-sizeof(long),id,0);//消息类型不符合堵塞
//msgrcv(msgid,&buf,sizeof(buf)-sizeof(long),id,IPC_NOWAIT);//消息类型不符合不堵塞
printf("%s\n",buf.strbuf);
msgctl(msgid,IPC_RMID,NULL);
return 0;
}
运行结果:
发送消息端:
[root@localhost examp]# gcc -o send IPCSEND.c
IPC21.c:68:2: 警告:文件未以空白行结束
/tmp/ccY2WDsl.o: In function main':
gets’ function is dangerous and should not be used.
IPC21.c:(.text+0x8e): warning: the
[root@localhost examp]# ./send IPC2.txt
571500EF
hello word
接收消息端:
[root@localhost examp]# gcc -o recv IPCRECV.c
[root@localhost examp]# ./recv IPC2.txt
571500EF
14 //注释:接收消息端必须发送消息类型
hello word
如有错误,欢迎指出。