System V 进程间通信(IPC)之System V 消息队列

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':
IPC21.c:(.text+0x8e): warning: the
gets’ function is dangerous and should not be used.
[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

如有错误,欢迎指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值