进程(五)(理解):IPC进程间通信:消息队列

一、IPC进程间通信相关命令

ipcs:查看当前系统中已经使用的IPC进程间通信(1.2.3)
		ipcs -q:单独查看消息队列
		ipcs -m: 单独查看共享内存
		ipcs -s:单独查看信号灯集
		
ipcrm:删除IPC进程间通信
		ipcrm -q msqid   删除消息队列号为msqid的消息队列
		ipcrm -m shmid   删除共享内存号为shmid的共享内存
		ipcrm -s semid   删除信号灯集号为semid的信号灯集

二、键值

ftok函数原理解析

#include <sys/types.h>
#include <sys/ipc.h>
函数原型:
    key_t ftok(const char *pathname, int proj_id);

参数:
     pathname:已经存在的文件路径以及名字 
     proj_id:任意一个字符或者数字,它的低八位有效   1    'a'
返回值:    
    成功返回获取的key键值, 失败返回-1
    
使用:若两个进程间需要建立通信,需要使用相同的键值。即两个参数相同。

三、消息队列

  • 消息队列也是借助内核实现,A进程将消息放入消息队列中,队列中的消息是一个结构体,由两部分组成,消息的类型和消息的正文,正文可以是字符串,整型,数组,结构体。
  • B进程可以根据想取的消息的类型将消息从队列中取走。消息队列的大小默认为16K(16384字节),如果消息队列中的消息满了,A进程就会写阻塞,
    什么时候B进程读取一个A进程才能继续写。
    1

四、 消息队列API(msgget / msgsnd / msgrcv / msgctl )

 四个函数头文件都如下:
       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/msg.h>
       
函数原型:
       int msgget(key_t key, int msgflg);

功能:创建消息队列
参数:@key:键值----通过ftok获取
            IPC_PRIVATE: 只能用于亲缘进程间通信(可以这么用,但是一般不用)
     @msgflg:消息队列的标志位
            IPC_CREAT:创建,比如使用时候(IPC_CREAT | 0666),
            		  如果这个时候消息队列已经存在了,会直接返回消息队列号
            IPC_EXCL: 如果消息队列已经存在,就报错
返回值:成功返回消息队列号,失败返回-1置位错误码
------------------------------------------------------------------

函数原型:
       int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:往消息队列里面发送数据
参数:
    @msqid:消息队列号
    @msgp:消息的首地址
         struct msgbuf {
               long mtype;       /* message type, must be > 0 */
               char mtext[1];    /* message data */
           };
    @msgsz: 消息正文的大小(不包含类型)
    @msgflg:消息的标志
            0         : 阻塞发送(如果写满16K 再往里面写会阻塞等,读取一个写进去一个)
            IPC_NOWAIT: 非阻塞发送数据(如果写满16K 再往里面写会直接报错返回)
返回值:成功返回0,失败返回-1置位错误码  
-----------------------------------------------------------------------------

 函数原型:
     ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
功能:从消息队列中获取数据
参数:
    @msgqid:消息队列号
    @msgp:消息的首地址
    @msgsz:消息正文的大小
    @msgtyp:消息的类型:
        如果=0:接受消息队列中的第一个消息
        如果>0:就会接收msgtyp指定的消息类型
        如果<0:就会读取队列中第一最小类型小于或等于msgtyp绝对值的消息
    @msgflg:消息的标志:
        0         : 阻塞接受(如果消息队列中没有消息,读的时候阻塞等,写进去一个读一个)
        IPC_NOWAIT: 非阻塞接收(如果消息队列中没有消息,读的时候直接报错返回)
返回值:成功返回接收到的字节个数,失败返回-1置位错误码
---------------------------------------------------------------------------

函数原型:
       int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:控制消息队列
参数:
    @msgqid:消息队列号
    @cmd: 命令
        IPC_STAT: 获取消息队列的属性
        IPC_SET: 设置消息队列的属性
        IPC_RMID: 立即删除消息队列
    @buf:消息队列属性的结构体 如果第二个参数为IPC_RMID,该参数传NULL即可
返回值:成功返回0 ,失败返回-1。

比如:msgctl(msgqid,  IPC_RMID,  NULL);    删除消息队列

五、示例:消息队列实现进程间通信

write.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
typedef struct {
   long mtype;          //必须为long    
   char mtext[128];
}msg_t;

int main(){
    //1. 创建键值
    key_t key;
    
    if((key = ftok("/home/linux/2307", 'a')) == -1){
        printf("ftok error\n");return -1;
    }
    
    //2. 创建消息队列
    int msqid;
    if(( msqid = msgget(key, IPC_CREAT | 0666)) == -1){
        printf("msgget error\n");return -1;
    }
    
    //3. 向消息队列中发送消息
    //创建结构体存放消息
    msg_t msg = {
        .mtype = 20,
    };
    
    while(1){
        printf("input > ");
        fgets(msg.mtext, sizeof(msg.mtext), stdin);
        msg.mtext[strlen(msg.mtext) - 1] = '\0';
        msgsnd(msqid, &msg, strlen(msg.mtext), 0);
        
        if(strcmp(msg.mtext, "quit") == 0)
            break;
    }
    return 0;
}

read.c

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>

typedef struct {
   long mtype;          //必须为long    
   char mtext[128];   
}msg_t;

int main(){
    //1. 创建键值
    key_t key;
    
    if((key = ftok("/home/linux/2307", 'a')) == -1){
        printf("ftok error\n");return -1;
    }
    
    //2. 得到消息队列号
    int msqid;
    if(( msqid = msgget(key, IPC_CREAT | 0666)) == -1){
        printf("msgget error\n");return -1;
    }
    
    //创建结构体
    msg_t msg;
    
    //3. 从消息队列中读取消息
    while(1){
        memset(&msg, 0, sizeof(msg));
        msgrcv(msqid, &msg, sizeof(msg.mtext), 20, 0);
        printf("type = %ld, msg = %s\n", msg.mtype, msg.mtext);
        
        if(strcmp(msg.mtext, "quit") == 0)
            break;
    }
    return 0;
}

write.c—2

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#define MSGSIZE (sizeof(msg_t)-sizeof(long))
typedef struct {
   long type;          //必须为long    
   char name[20];
   int age;
   char sex;
}msg_t;

int main(){
    //1. 创建键值
    key_t key;
    
    if((key = ftok("/home/linux/2307", 'a')) == -1){
        printf("ftok error\n");return -1;
    }
    
    //2. 得到消息队列号
    int msqid;
    if(( msqid = msgget(key, IPC_CREAT | 0666)) == -1){
        printf("msgget error\n");return -1;
    }
    
    //创建消息结构体          往息队列中发送消息
    msg_t msg1 = {
        .type = 1,
        .name = "zhangsan",
        .age = 18,
        .sex = 'm',
    };
    msgsnd(msqid, &msg1, MSGSIZE, 0);
    
    msg_t msg2 = {
        .type = 2,
        .name = "lisi",
        .age = 20,
        .sex = 'm',
    };
    msgsnd(msqid, &msg2, MSGSIZE, 0);
    
    msg_t msg3 = {
        .type = 3,
        .name = "disange",
        .age = 20,
        .sex = 'w',
    };
    msgsnd(msqid, &msg3, MSGSIZE, 0);
    
    msg_t msg4 = {
        .type = 4,
        .name = "disige",
        .age = 20,
        .sex = 'w',
    };
    msgsnd(msqid, &msg4, MSGSIZE, 0);
    
    return 0;
}

read.c --2

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>
#define MSGSIZE (sizeof(msg_t)-sizeof(long))
typedef struct {
   long type;          //必须为long    
   char name[20];
   int age;
   char sex;
}msg_t;


int main(int argc, const char *argv[]){
    //1. 创建键值
    key_t key;
    
    if((key = ftok("/home/linux/2307", 'a')) == -1){
        printf("ftok error\n");return -1;
    }
    
    //2. 创建消息队列
    int msqid;
    if(( msqid = msgget(key, IPC_CREAT | 0666)) == -1){
        printf("msgget error\n");return -1;
    }
    
    //3. 从消息队列中读取消息
    msg_t msg;
    
    memset(&msg, 0, sizeof(msg));
    msgrcv(msqid, &msg, MSGSIZE, 1, 0);
    printf("type = %ld,  name = %s, age = %d,  sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
    
    memset(&msg, 0, sizeof(msg));
    msgrcv(msqid, &msg, MSGSIZE, 2, 0);
    printf("type = %ld,  name = %s, age = %d,  sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
    
    memset(&msg, 0, sizeof(msg));
    msgrcv(msqid, &msg, MSGSIZE, 3, 0);
    printf("type = %ld,  name = %s, age = %d,  sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
    
    memset(&msg, 0, sizeof(msg));
    msgrcv(msqid, &msg, MSGSIZE, 4, 0);
    printf("type = %ld,  name = %s, age = %d,  sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
    
    /*
    memset(&msg, 0, sizeof(msg));
    msgrcv(msqid, &msg, MSGSIZE, atoi(argv[1]), 0);
    printf("type = %ld,  name = %s, age = %d,  sex = %c\n", msg.type, msg.name, msg.age, msg.sex);
    */
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好好睡觉好好吃饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值