Linux_进程间通信_2)消息队列

一,本质

     内核中提供的链表

二.特性

     1)消息队列提供了一个从一个进程向另外一个进程发送一块数据的方式(可用于任何进程之间)

     2)每个数据块都被认为是有一个类型,接受者进程接受的数据块可以有不同的类型值5)

     3)双向通信,全双工

     4)面向数据报

     5)内置了同步互斥机制

     6)生命周期随内核(会一直存在,直到显式删除或者系统重启)

     7)限制:每个消息的最大长度有限,每个消息队列的总的字节数也是有上限的,系统上消息队列的总的个数也是有限的。

三.工作方式

     

       AB代表两个进程,从哪个通道发送就从哪个通道接收,发送了没接收就堵塞在通道中,接收方什么时候打开什么时候接收。

四.API

     1)创建和访问一个消息队列

            a)头文件:#include <sys/types.h>
                                  #include <sys/ipc.h>
                                  #include <sys/msg.h>

            b)函数原型:int msgget(key_t key, int msgflg);

        c)函数参数:key 消息队列的名字 msgget 由九个权限标志构成,用法和创建文件的mode一样(打开0,创建IPC_CREAT|0644)

            d)返回值:成功返回非负整数,即消息队列的标识码,失败返回-1

            e)栗子

  7 int main(void){
  8     int key;
  9     key_t msg=001;                                                                                                   
 10     key=msgget(msg,IPC_CREAT|0644);
 11     if(key==-1) perror("msgget"),exit(1);
 12     return 0;
 13 }

    2)删除消息队列

         a)头文件:和msgget一样

         b)函数原型:  int msgctl(int msqid, int cmd, struct msqid_ds *buf);

         c)参数:msqid 是msgget返回的消息队列的标识码  第三个参数删除时不关注写0

                           cmd有三个可取值:IPC_STAT把结构体msqid_ds中的数据设置为消息队列的当前关联值

                                                              IPC_SET在进程有足够权限的前提下,把消息队列的关联值设置为msqid_ds结构体给出的值

                                                              IPC_RMID删除消息队列

        d)返回值:成功返回0,失败返回-1

   3)将一条消息添加到消息队列中

        a)头文件:和msgget一样

        b)函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

        c)参数:msqid 是msgget返回的消息队列的标识码 msgp 是一个指针,指针指向准备发送的信息

                          msgsz:是msgp指向的消息的长度,长度不包含保存消息类型的longint的大小

                          msgflg:控制当前消息队列满或者达到系统上限时将要发生的事(IPC_NOWAIT表示队列满不等待,返回EAGAIN错误)(一般写0)

       d)返回值:成功返回0,失败返回-1

       e)发送消息的结构有两点制约:小于系统规定的上限值,必须以一个long int长整数开始

              通常发送一个结构体 struct msgbuf{long channel,char mtext[1024]};

  4)接收消息队列中的消息

       a)头文件:和msgget一样

       b)函数原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

       c)参数:msqid 是msgget返回的消息队列的标识码 ,msgp 是一个指针,指针指向准备发送的信息

                         msgsz:是msgp指向的消息的长度,长度不包含保存消息类型的longint的大小

                         msgtype:可以实现接收优先级的简单形式(为0返回队列的第一条消息,大于0返回队列第一条类型等于msgtype的消息,小于0返回队列第一条类型小于等于msgtype绝对值的消息,并且满足条件的消息类型最小的消息)

                         msgflag:控制着队列中没有相应类型的消息可供接受时将要发生的事(为IPC_NOWAIT,队列没有可读消息不等待,返回ENOMSG错误,为MSG_NOERROR,消息大小超过msgsz时被截断)

                          msgtype>0且msgflg=MSG_EXCEPT,接收类型不等于msgtype的第一条消息

       d)返回值:成功返回放入接收缓冲区里的字符个数,失败返回-1

插播一段代码

comm.h

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 #include <sys/ipc.h>
  5 #include <sys/msg.h>
  6 struct msgbuf{
  7     long mtype; //几号通道
  8     char text[1024];
  9 };
 10 
 11 #define SEVER 1
 12 #define CLIENT 2
 13 
 14 #define PATHNAME "."
 15 #define ID 0x001
 16 
 17 int CreateMsg(int flags);
 18 int Sendmsg(int msgid,char * msg,int channel);
 19 int Recmsg(int msgid,int channel,char * out);
 20 int Destorymsg(int msgid);

comm.c

  1 #include "comm.h"
  2 
  3 int CreateMsg(int flags){
  4     key_t key=ftok(PATHNAME,ID);
  5     if(key<0){
  6         perror("ftok");
  7         return 1;
  8     }
  9 
 10     int msggid;
 11     if(flags==0){
 12         msggid=msgget(key,IPC_CREAT|0644);
 13     }else if(flags==1){
 14         msggid=msgget(key,0);
 15     }
 16     if(msggid<0){
 17         perror("msggid");
 18         return 1;
 19     }
 20 
 21     return msggid;
 22 }
 23 
 24 int Destorymsg(int msgid){
 25     int del=msgctl(msgid,IPC_RMID,0);
 26     
 27     if(del<0){
 28         perror("msgctl");
 29         return -1;
 30     }
 31     return 0;
 32 }
 33 
 34 int Sendmsg(int msgid,char * msg,int channel){
 35     struct msgbuf buf;
 36     buf.mtype=channel;
 37     strcpy(buf.text,msg);
 38 
 39     int sen=msgsnd(msgid,&buf,strlen(buf.text),0);
 40     if(sen<0){
 41         perror("msgsnd");
 42         return -1;
 43     }
 44     return 0;
 45 }
 46 
 47 int Recmsg(int msgid,int channel,char * out){
 48     struct msgbuf buf;
 49     buf.mtype=channel;
 50     memset(buf.text,0x00,sizeof(buf.text));
 51 
 52     int rec=msgrcv(msgid,&buf,sizeof(buf.text),channel,0);
 53     if(rec<0){
 54         perror("msgrcv");
 55         return -1;
 56     }
 57     strcpy(out,buf.text);
 58     return 0;
 59 }

client.c

  1 #include "comm.h"
  2 
  3 int main(void){
  4     int msgid=CreateMsg(1);
  5 
  6     char buf[1024]={0};
  7 
  8     while(1){
  9         printf("Client say#");
 10         fflush(stdout);
 11         int ret=read(0,buf,sizeof(buf));
 12         if(ret<=0) break;
 13         else
 14             buf[ret-1]=0;
 15 
 16         Sendmsg(msgid,buf,CLIENT);
 17         memset(buf,0x00,sizeof(buf));
 18 
 19         Recmsg(msgid,SEVER,buf);
 20         printf("Sever say#%s\n",buf);
 21             
 22     }
 23     return 0;
 24 }                

sever.c

  1 #include "comm.h"
  2 
  3 int main(void){
  4     int msgid=CreateMsg(0); //create
  5 
  6     int ret;
  7     char buf[1024];
  8     while(1){
  9         Recmsg(msgid,CLIENT,buf);
 10         printf("Client say#:%s\n",buf);
 11 
 12         memset(buf,0x00,sizeof(buf));
 13         printf("Seversay#");
 14         fflush(stdout);
 15         ret=read(0,buf,sizeof(buf));
 16         if(ret<=0)
 17             break;
 18         else
 19             buf[ret-1]=0;
 20         if(strncmp(buf,"exit",4)==0)
 21             break;
 22         Sendmsg(msgid,buf,SEVER);
 23     }
 24     Destorymsg(msgid);
 25     return 0;
 26 }                    

Makefile

  2 .PHONY:all
  3 all:client sever
  4 
  5 client:client.c comm.c
  6     gcc -o $@ $^
  7 
  8 sever:sever.c comm.c
  9     gcc -o $@ $^
 10 
 11 .PHONY:clean
 12 
 13 clean:
 14     rm -f client sever      

用消息队列实现了客户端和服务器间简单的消息传送 

在写代码中遇到的问题:Makefile中由于vimrc中设置了set expandtab  总是报三号错误,改成set noexpandtab  就好啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值