您的位置:首页 > 其它

进程通信(消息队列)

2016-06-12 12:46 513 查看
消息队列与管道不同的是,消息队列是基于消息的,
而管道是基于字节流的,且消息队列的读取不一定是先入先出。消息队列与命名管道有一
样的不足,就是每个消息的最大长度是有上限的(MSGMAX),每个消息队列的总的字节
数是有上限的(MSGMNB),系统上消息队列的总数也有一个上限(MSGMNI)。

IPC对象数据结构
内核为每个IPC对象维护一个数据结构(/usr/include/linux/ipc.h)
struct ipc_perm {
key_t __key; /* Key supplied to xxxget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions */
unsigned short __seq; /* Sequence number */
};

1.创建新消息队列或取得已存在消息队列
原型:int msgget(key_t key, int msgflg);
参数:
key:可以认为是一个端口号,也可以由函数ftok生成。
msgflg:
IPC_CREAT 如果IPC不存在,则创建一个IPC资源,否则打开操作。
IPC_EXCL:只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。
如果单独使用IPC_CREAT,XXXget()函数要么返回一个已经存在的共享内存的操作符,要
么返回一个新建的共享内存的标识符。
如果将IPC_CREAT和IPC_EXCL标志一起使用,XXXget()将返回一个新建的IPC标识符
;如果该IPC资源已存在,或者返回-1。
IPC_EXEL标志本身并没有太大的意义,但是和IPC_CREAT标志一起使用可以用来保证
所得的对象是新建的,而不是打开已有的对象。

2.向队列读/写消息
原型:
msgrcv从队列中取用消息:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int
msgflg);
msgsnd将数据放到消息队列中:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msqid:消息队列的标识码
msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可
定义的通用结构,形态如下:
struct msgstru{
long mtype; //大于0
char mtext[用户指定大小];
};
msgsz:消息的大小。

msgtyp:从消息队列内读取的消息形态。如果值为零,则表示消息队列中的所有消息都
会被读取。

msgflg:用来指明核心程序在队列没有数据的情况下所应采取的行动。如果msgflg和常
数IPC_NOWAIT合用,则在msgsnd()执行时若是消息队列已满,则msgsnd()将不会阻塞,而
会立即返回-1,如果执行的是msgrcv(),则在消息队列呈空时,不做等待马上返回-1,并设定
错误码为ENOMSG。当msgflg为0时,msgsnd()及msgrcv()在队列呈满或呈空的情形时,采取
阻塞等待的处理模式。

3.设置消息队列属性
原型:int msgctl ( int msgqid, int cmd, struct msqid_ds *buf );
参数:msgctl 系统调用对 msgqid 标识的消息队列执行 cmd 操作,系统定义了 3 种 cmd 操作
: IPC_STAT , IPC_SET , IPC_RMID
IPC_STAT : 该命令用来获取消息队列对应的 msqid_ds 数据结构,并将其保存到 buf 指
定的地址空间。
IPC_SET : 该命令用来设置消息队列的属性,要设置的属性存储在buf中。
IPC_RMID : 从内核中删除 msqid 标识的消息队列。

key_t键
System V IPC使用key_t值作为它们的名字,在Redhat linux(后续验证默认都在该平台下)下
key_t被定义为int类型
ftok函数
函数ftok把一个已存在的路径名和一个整数标识得转换成一个key_t值,称为IPC键:
# include <sys/types.h>
# include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
该函数把从pathname导出的信息与id的低序8位组合成一个整数IPC键。

comm.h
  1 #pragma once
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 #include<sys/ipc.h>
  6 #include<sys/types.h>
  7 #include<sys/msg.h>
  8 #define _PATH_ ".tmp"
  9 #define SIZE 100
 10 #define _PROJ_ID 0x444
 11 #define _client_ 2
 12 #define _server_ 1
 13 
 14 typedef struct _msginfo
 15 {
 16   long mtype;
 17   char mtext[SIZE];
 18 }msginfo;
 19 int create_msg_set();
 20 int get_msg_set();
 21 int rec_msg_set(int,char*,long);
 22 int send_msg_set(int,char*,long);
 23 int destroy_msg_set(int);
 
 
 comm.c
  1 #include "comm.h"
  2 static int com_creat_msg_set(int flags)
  3 {
  4   key_t key=ftok(_PATH_,_PROJ_ID);
  5   if(key<0)
  6   {
  7    perror("ftok");
  8   return -1;
  9   }
 10   int _msg_id=msgget(key,flags);
 11   if(_msg_id<0)
 12   {
 13    perror("msgget");
 14    return -1;
 15   }
 16 return _msg_id;
 17 }
 18 int creat_msg_set()
 19 {
 20   int flags=IPC_CREAT|IPC_EXCL|0666;
 21   return com_creat_msg_set(flags);
 22 }
 23 int get_msg_set()
 24 {
 25 
 26   int flags=IPC_CREAT;
 27   return com_creat_msg_set(flags);
 28 }
 29 
 30 int rec_msg_set(int _msg_id,char* msg,long mtype)
 31 {
 32 
 33   msginfo _info;
 34   memset(_info.mtext,'\0',sizeof(_info.mtext));
 35  if(msgrcv(_msg_id,&_info,SIZE-1,mtype,0)<0)
 36 {
 37   perror("msgrcv");
 38   return -1;
 39 }
 40 strcpy(msg,_info.mtext);
 41 return 0;
 42 }
 43 
 44 
 45 int send_msg_set(int _msg_id,char *msg,long mtype)
 46 {
 47 
 48   msginfo _info;
 49   memset(_info.mtext,'\0',sizeof(_info.mtext));
 50   strcpy(_info.mtext,msg);
 51 //  gets(_info.mtext);
 52  _info.mtype=mtype;
 53  if(msgsnd(_msg_id,&_info,strlen(_info.mtext),0)<0)
 54 {
 55   perror("msgsnd");
 56   return -1;
 57 }
 58  return 0;
 59 
 60 }
 61 
 62 
 63 int destroy_msg_set(int _msg_id)
 64 {
 65   if(msgctl(_msg_id,IPC_RMID,NULL)<0)
 66   {
 67    perror("msgctl");
 68    return -1;
 69   }
 70   return 0;
 71 }
                                                                                          
                                                                                          client.c
                                                                                           1 
  2 #include "comm.h"
  3 int main()
  4 {
  5   int _msg_id=creat_msg_set();
  6   char msg[SIZE];
  7   while(1)
  8   {
  9     fflush(stdout);
 10     printf("client:");
 11     memset(msg,'\0',SIZE);
 12     scanf("%s",msg);
 13     send_msg_set(_msg_id,msg,_client_);
 14     //sleep(5);
 15     memset(msg,'\0',SIZE);
 16     printf("server:\n");
 17     rec_msg_set(_msg_id,msg,_server_);
 18     printf("%s",msg);
 19 
 20   }
 21   destroy(_msg_id);
 22   return 0;
 23 }

  server.c
  1 #include "comm.h"
  2 int main()
  3 {
  4   int _msg_id=get_msg_set();
  5   char msg[SIZE];
  6   while(1)
  7   {
  8     //sleep(5);
  9     printf("client:");
 10     rec_msg_set(_msg_id,msg,_client_);
 11     printf("%s",msg);
 12     fflush(stdout);
 13     memset(msg,'\0',sizeof(msg));
 14     //sleep(5);
 15     printf("server:\n");
 16     scanf("%s",msg);
 17     send_msg_set(_msg_id,msg,_server_);
 18 
 19   }
 20   return 0;
 21 }
      
      
 Makefile:
                                                                                           1 .PHONY:all
  2 all:client server
  3 client: client.c comm.c
  4     gcc -o $@ $^
  5 server:server.c comm.c
  6     gcc -o $@ $^
  7 .PHONY:clean
  8 clean:
  9     rm -f client server 
   
  
  结果:
[admin@localhost message]$ ./client
client:naihao
server:
woclient:
nihao
server:
aiclient: 

 [admin@loc
4000
alhost message]$ ./server
client:naihaoserver:
wo ai ni
client:nihaoserver:
niaho


本文出自 “liveyoung” 博客,转载请与作者联系!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: