作用
进程间通信
特点
1 、消息队列中的消息是有类型的。类型 : 自定义的结构体 , 第一个成员必须是 long 型的 . 表示为该消息的类型如 :typedef struct 结构体名称 {long type;// 消息的正文char name[50];char sex[10];int age;...} 别名 ;2 、消息队列中的消息是有格式的。3 、消息队列可以实现消息的随机查询。消息不一定要以先进先出的次序读取,编程时可以按消息的类型读取。发的顺序 :1 2 1 3读 :3,1,1,24 、消息队列允许一个或多个进程向它写入或者读取消息。5 、与无名管道、命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删除。6 、每个消息队列都有消息队列标识符,消息队列的标识符在整个系统中是唯一的。7 、只有内核重启或人工删除消息队列时,该消息队列才会被删除。若不人工删除消息队列,消息队列会一直存在于系统中。
消息队列限制值如下:
每个消息内容最多为 8K 字节每个消息队列容量最多为 16K 字节系统中消息队列个数最多为 1609 个系统中消息个数最多为 16384 个
注意
System V 提供的 IPC 通信机制需要一个 key 值,通过 key 值就可在系统内获得一
个唯一的消息队列标识符。key 值可以是人为指定的,也可以通过 ftok 函数获得。ftok 函数当参数相同时 , 得到的 key 值也将相同
相关命令
ipcs -q
ipcrm -q 要删除的消息队列 id
ftok函数
作用
获取key值
语法
key_t ftok(const char *pathname, int proj_id);
参数 :pathname: 文件地址 , 保证是存在的路径就行如 :/~./proj_id: 项目 id, 随便给返回值 :计算得到的 key 值
msgget函数
作用
获取消息队列
语法
头文件
#include <sys/msg.h>函数int msgget(key_t key, int msgflg) ;功能:创建一个新的或打开一个已经存在的消息队列。不同的进程调用此函数,只要用相同的 key 值就能得到同一个消息队列的标识符。参数:key : IPC 键值。msgflg :标识函数的行为及消息队列的权限。msgflg 的取值:IPC_CREAT :创建消息队列。IPC_EXCL :检测消息队列是否存在。位或权限位:消息队列位或权限位后可以设置消息队列的访问权限,格式和open 函数的 mode_t 一样,但可执行权限未使用。如 :IPC_CREAT | 0666如果消息队列不存在 , 则创建该消息队列 , 所有用户可读可写如果消息队列以存在 , 则使用已经存在的消息队列返回值 :创建的消息队列的 id, 失败返回 -1
msgsnd函数
作用
发送消息
函数
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数 :msqid: 消息队列 idmsgp: 发送的消息的结构体指针msgsz: 发送的消息的正文大小msgflg: 标记0 : msgsnd 调用阻塞直到条件满足为止。IPC_NOWAIT: 若消息没有立即发送则调用该函数的进程会立即返回。返回值 :成功 0, 失败 -1
msgrcv函数
作用
接收消息
函数
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int
msgflg);参数 :msqid: 消息队列 idmsgp: 接收消息的结构体指针变量msgsz: 接收的消息的正文大小msgtyp: 接收的消息的类型msgflg: 标记0 : msgsnd 调用阻塞直到条件满足为止。IPC_NOWAIT: 若消息没有立即发送则调用该函数的进程会立即返回。
基于消息队列的聊天程序
思路
1,请输入昵称
2, 请输入接收的消息类型3, 创建消息队列4, 创建两个子进程 , 一个接收消息 , 一个发送消息5, 当前进程回收子进程
代码
#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#include <time.h>#include <stdlib.h>#include <unistd.h>#include <wait.h>typedef struct message{long type;char name[50];char info[300];char t[50];}MSG;char* getTimer(){time_t tim;time(&tim);struct tm* t =localtime(&tim);char *tstr = calloc(50,sizeof(char));sprintf(tstr,"%d 年 %02d 月 %02d 日 %02d:%02d:%02d\n",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);return tstr;}int main(int argc, char const *argv[]){char name[50] = {0};printf(" 请输入您的昵称 \n");fgets(name,50,stdin);long type = 0;printf(" 请输入您接收的消息的类型 \n");scanf("%ld",&type);int key = ftok("/",777);int msgid = msgget(key,IPC_CREAT | 0666);int i = 0;for (i = 0; i < 2; i++){int pid = fork();if (pid == 0){break;}}if (i == 0){while(1){// 发MSG m;strcpy(m.name,name);printf(" 请输入接收方接收的类型 \n");scanf("%ld",&(m.type));printf(" 请输入发送的内容 \n");scanf("%s",m.info);strcpy(m.t,getTimer());msgsnd(msgid,&m,sizeof(MSG)-sizeof(long),0);if (strcmp(m.info,"886") == 0){break;}}}if (i == 1){// 接while(1){MSG m;msgrcv(msgid,&m,sizeof(MSG)-sizeof(long),type,0);printf("%s(%s) 说 :\n\t%s\n",m.name,m.t,m.info);if (strcmp(m.info,"886") == 0){break;}}}if (i == 2){while(waitpid(-1,NULL,WNOHANG) != -1); }return 0;}