消息队列与管道不同的是,消息队列是基于消息的, 而管道是基于字节流的,且消息队列的读取不一定是先入先出。消息队列与命名管道有一 样的不足,就是每个消息的最大长度是有上限的(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 [email protected] $^ 5 server:server.c comm.c 6 gcc -o [email protected] $^ 7 .PHONY:clean 8 clean: 9 rm -f client server 结果: [[email protected] message]$ ./client client:naihao server: woclient: nihao server: aiclient: [[email protected] message]$ ./server client:naihaoserver: wo ai ni client:nihaoserver: niaho
时间: 2024-10-10 04:35:50