进程间通信——消息队列

1.什么是消息队列?

消息队列是消息的链接表 ,存放在内核中并由消息队列标识符标识。我们将称消息队列为“队列”,其标识符为“队列I D”。

2.函数介绍

2.1msgget函数

1,调用的第一个函数通常是m s g g e t,其功能是打开一个现存队列或创建一个新队列。

2,函数原型:

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

int msgget(key_t  key, int flag) ;   
//返回:若成功则为消息队列I D,若出错则为- 1

第一个参数key:0(IPC_PRIVATE):会建立新的消息队列;大于0的32位整数:视参数msgflg来确定操作。通常要求此值来源于ftok返回的IPC键值。
第二个参数flag:0:取消息队列标识符,若不存在则函数会报错;IPC_CREAT:当msgflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回此消息队列的标识符IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列则报错。

2.2msgctl函数

1,msgctl函数对队列执行多种操作。
2,函数原型:

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

int msgctl(int msqid, int cmd, struct msqid_ds *buf)
//返回:若成功则为0,出错则为- 1

第一个参数msqid:消息队列标识符
第二个参数cmd:IPC_STAT:获得msgid的消息队列头数据到buf中IPC_SET:设置消息队列的属性,要设置的属性需先存储在buf中,可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes。

2.3msgsnd函数

1,调用msgsnd将数据放到消息队列上。
2,函数原型:

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

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)

//返回:若成功则为0,若出错则为- 1

第一个参数msqid:消息队列标识符
第二个参数msgp:发送给队列的消息。msgp可以是任何类型的结构体,但第一个字段必须为long类型,即表明此发送消息的类型,msgrcv根据此接收消息。msgp定义的参照格式如下:

 struct s_msg
 {/*msgp定义的参照格式*/     
             long    type; /* 必须大于0,消息类型 */          
             char    mtext[256]; /*消息正文,可以是其他任何类型*/    
 } msgp; 

第三个参数msgsz:发送消息的大小,不含消息类型占用的4个字节,(mtext长度)
第四个参数msgflg:0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。

2.4msgrcv函数

1,msgrcv 用于从消息队列读取消息
2,函数原型

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

int msgrcv(int msqid, void * ptr, size_t nbytes, long type, int flag) ;

//返回:若成功则为消息数据部分的长度,若出错则为 - 1

第一个参数msqid:消息队列标识符
第二个参数ptr:存放消息的结构体,结构体类型要与msgsnd函数发送的类型相同
第三个nbytes:要接收消息的大小,不含消息类型占用的4个字节
第四个type:
0:接收第一个消息 > 0:接收类型等于msgtyp的第一个消息
<0:接收类型等于或者小于msgtyp绝对值的第一个消息
第五个flag:0: 阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待

3,msgrcv()解除阻塞的条件有以下三个:
① 消息队列中有了满足条件的消息。
② msqid代表的消息队列被删除。
③ 调用msgrcv()的进程被信号中断。

3.应用实例

1发送端:

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

#define MAX_TEXT 512

struct msg_struct   //表明发送信息的结构体
{
    long  msg_type;
    char  msg_text[MAX_TEXT];
}msg_st;


int main()
{
     int                     msgid = -1;
     int                     starting = 1;    
     long int                msgtype = 0;
     struct msg_struct       data;
     char                    buffer[BUFSIZ];


     msgid = msgget((key_t)1234, 0666 | IPC_CREAT);  //建立消息队列
     
     if(msgid < 0 )
     { 
           printf("creta msgget failure\n");
           return -1;      
     } 
     printf("creat msgget successful\n");

     while(starting)        //输入数据
     {
           printf("请输入消息:\n");
           fgets(buffer, BUFSIZ, stdin);    
           data.msg_type = 1;  
          
           // 向队列发消息 
           strcpy(data.msg_text, buffer); 


            if(msgsnd(msgid,(void*)&data,MAX_TEXT , 0) <0 )
            {
                  printf("msgsnd errno :%d\n", errno);
                  return -2;
            }   
            
            // 输入end时则结束对话
            if(strncmp(buffer, "end", 3) == 0)
                  starting = 0;

             sleep(1); 
     }
     
   
     return 0;
}

2接收端:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h> 


struct msg_struct
{   
    long int   msg_type;  
    char       msg_text[BUFSIZ];
}msg_st; 




int main()
{   
    int                  starting = 1;    
    int                  msgid = -1;
    struct msg_struct    data;
    long int             msgtype = 0;     
   
    //建立消息队列    
    msgid = msgget((key_t)1234, 0666 | IPC_CREAT);  
   
    if(msgid <0 ) 
    {       
        printf("msgget failed with error: %d\n", errno);   
        return -1; 
    }  
   

    //从队列中获取消息,直到遇到end消息为止  
    while(starting)  
    {   
        if(msgrcv(msgid, (void*)&data, BUFSIZ, msgtype, 0) < 0)   
        {   
            printf("msgrcv failed with errno: %d\n", errno);   
            return -2;     
        }   
        printf("You wrote: %s\n",data.msg_text);     
     
        //遇到end结束   
        if(strncmp(data.msg_text, "end", 3) == 0)       
            starting = 0;    
    }  

     //删除消息队列    
    if(msgctl(msgid, IPC_RMID, 0) == -1)    
    {       
        printf("msgctl(IPC_RMID) failed\n");   
        return -3; 
    }   
    
    return 0;
}

3.1结果展示

先分别打开两个程序,首先打开客户端:
在这里插入图片描述
然后打开接收端:
在这里插入图片描述
在客户端输入信息在这里插入图片描述
直到输入end时 程序终止。
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值