Linux进程间通信——使用消息队列 消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。

Linux进程间通信——使用消息队列

消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。

----->双向通信

----->用于随意进程

------>面向数据块(链表)

------>自带同步互斥

------->生命周期随内核

消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。

可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。

进程间通过消息队列通信,主要是:创建或打开消息队列,添加消息,读取消息和控制消息队列

消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

消息队列也有管道一样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)------Linux用宏MSGMAX和MSGMNB来限制一条消息的最大长度和一个队列的最大长度。

Linux提供了一系列消息队列的函数接口来让我们方便地使用它来实现进程间的通信

1、msgget函数
该函数用来创建和访问一个消息队列。它的原型为:
int msgget(key_t key, int msgflg); 

      key  -->某个消息队列的名字

      msgflg  -->由9个权限标识符构成,

返回值:成功时返回一个非负整数,即该消息队列的标识符,失败返回-1.

2、msgsnd函数
该函数用来把消息添加到消息队列中。它的原型为:
int msgsend(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg);  
msgid是由msgget函数返回的消息队列标识符。
msg_ptr是一个指向准备发送消息的指针,但是消息的数据结构却有一定的要求,指针msg_ptr所指向的消息结构一定要是以一个长整型成员变量开始的结构体(由调用者定义的结构体,相当于链表的一个节点),接收函数将用这个成员来确定消息的类型。所以消息结构要定义成这样:
struct msgbuf{
     long mtype;//消息的类型
     char mtext[1];消息数据

};

msg_sz是msg_ptr指向的消息的长度,注意是消息的长度,而不是整个结构体的长度,也就是说msg_sz是不包括长整型消息类型成员变量的长度。(结构里mtext数组的大小)

msgflg用于控制当前消息队列满或队列消息到达系统范围的限制时将要发生的事情。如果调用成功,消息数据的一分副本将被放到消息队列中,并返回0,失败时返回-1.

3、msgrcv函数
该函数用来从一个消息队列获取消息,它的原型为
int msgrcv(int msgid, void *msg_ptr, size_t msg_st, long int msgtype, int msgflg);  
msgid, msg_ptr, msg_st的作用也函数msgsnd函数的一样。
msgtype可以实现一种简单的接收优先级。如果msgtype为0,就获取队列中的第一个消息。如果它的值大于零,将获取具有相同消息类型的第一个信息。如果它小于零,就获取类型等于或小于msgtype的绝对值的第一个消息。
msgflg用于控制当队列中没有相应类型的消息可以接收时将发生的事情。调用成功时,该函数返回放到接收缓存区中的字节数,消息被复制到由msg_ptr指向的用户分配的缓存区中,然后删除消息队列中的对应消息。失败时返回-1.
4、msgctl函数
该函数用来控制消息队列,它的原型为:
int msgctl(int msgid, int command, struct msgid_ds *buf);  
command是将要采取的动作,它可以取3个值,
    IPC_STAT:把msgid_ds结构中的数据设置为消息队列的当前关联值,即用消息队列的当前关联值覆盖msgid_ds的值。
    IPC_SET:如果进程有足够的权限,就把消息列队的当前关联值设置为msgid_ds结构中给出的值
    IPC_RMID:删除消息队列
buf是指向msgid_ds结构的指针,它指向消息队列模式和访问权限的结构。msgid_ds结构至少包括以下成员:
struct msgid_ds
{       uid_t shm_perm.uid; 
       uid_t shm_perm.gid; 

       mode_t shm_perm.mode; 

};  
成功时返回0,失败时返回-1.

代码实例:

系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值。通常情况下,该id值通过ftok函数得到。

ftok原型如下:

key_t ftok( char * fname, int id )

fname就时你指定的文件名(该文件必须是存在而且可以访问的),id是子序号,虽然为int,但是只有8个比特被使用(0-255)。

当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。

server.c

  1 #include "messages.h"
  2 int main(){
  3    int msgid = createMsgQueue();
  4    char buf[1024];
  5    while(1){
  6    buf[0]=0;
  7    recvMsg(msgid,CLIENT_TYPE,buf);
  8    printf("client# %s\n", buf);
  9    fflush(stdout);
 10    ssize_t s = read(0,buf,sizeof(buf));
 11    if(s>0){
 12       buf[s-1]=0;
 13      sendMsg(msgid,SERVER_TYPE,buf);
 14     printf("send done,wait recv...\n");
 15    }
 16    }                                                                                                                 
 17   destroyMsgQueue(msgid);
 18   return 0;
 19 }

client.c

  1 #include "messages.h"
  2 #include<stdio.h>
  3 int main(){
  4    int msgid = getMsgQueue();
  5    char buf[1024];
  6    while(1){
  7      buf[0]=0;
  8      printf("please enter# ");
  9      fflush(stdout);
 10      size_t s = read(0,buf,sizeof(buf));
 11      if(s>0){
 12      buf[s-1]=0;
 13      sendMsg(msgid,CLIENT_TYPE,buf);                                                                                 
 14      printf("send done,wait recv...\n");
 15      }
 16    }
 17    return 0;
 18 }

messages.c

  1 #include "messages.h"
  2 static int commMsgQueue(int flags){
  3    key_t key = ftok(PATHNAME,PROJ_ID);
  4    if(key<0){
  5     perror("ftok");
  6     return -1;
  7     }
  8     int msgid = msgget(key,flags);
  9     if(msgid<0){
 10       perror("msgget");
 11     }
 12    return msgid;
 13 }
 14 int createMsgQueue()
 15 {
 16    return commMsgQueue(IPC_CREAT|IPC_EXCL|0666);
 17 
 18 }
 19 int getMsgQueue(){
 20    return commMsgQueue(IPC_CREAT);
 21 }
 22 int destroyMsgQueue(int msgid){
 23 //控制消息队列
 24    if(msgctl(msgid,IPC_RMID,NULL)<0){
 25       perror("msgctl");
 26       return -1;
 27 }
 28 return 0;
 29 }
 30 int sendMsg(int msgid,int who,char *msg){
 31      struct msgbuf buf;
 32      buf.mtype = who;
 33      strcpy(buf.mtext,msg);
 34      //把消息添加到队列中
 35      if(msgsnd(msgid,(void *)&buf,sizeof(buf.mtext),0)<0){
 36         perror("msgnd");
 37         return -1;
 38    }
 39    return 0;
 40 }
 41 int recvMsg(int msgid,int recvType,char out[]){
 42     struct msgbuf buf;
 43     if(msgrcv(msgid,(void*)&buf,sizeof(buf.mtext),recvType,0)<0){
 44      perror("msgrcv");
 45      return -1;
 46     
 47 }

messages.h

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<string.h>
#define PATHNAME "."
#define PROJ_ID 0x6666
#define SERVER_TYPE 1
#define CLIENT_TYPE 2
struct msgbuf{
 long mtype;
char mtext[1024];
};
int createMsgQueue();
int getMsgQueue();
int destoryMsgQueue(int msgid);
int sendMsg(int msgid,int who,char *msg);
int recvMsg(int msgid,int recvType,char out[]); 

猜你喜欢

转载自blog.csdn.net/sx2448826571/article/details/79670086