进程间通信-消息传递机制

报告需要包含:实验内容原理性和实现细节解释,包括每个系统调用的作用过程和结果。

编译运行Algorithms 9.1~9.2

msgget():
函数原型:int msgget(key_t key, int msgflag)
作用:用于创建一个新的或打开一个已经存在的消息队列,此消息队列与key相对应。
参数:

  • key:函数ftok()的返回值,IPC_PRIVATE
  • msgflag:
    • IPC_CREAT:创建新的消息队列
    • IPC_EXCL:与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误。
    • IPC_NOWAIT:读写消息队列要求无法满足时,不阻塞
      返回值:
  • 成功返回队列标识符
  • 失败返回-1
    在以下两种情况下,将创建一个新的消息队列:
  1. 如果key为IPC_PRIVATE。
  2. key不是IPC_PRIVATE,并且key所对应的消息队列不存在,同时标志中指定IPC_CREAT
    使用说明:
#include<sys/ipc.h>
#include<sys/msg.h>
int msgget(key_t key, int msgflg);
  • key:消息队列关联的键
  • msgflag:消息队列的建立标志和存取权限
  • IPC_CREAT:如果内核中没有此队列,则创建它
  • IPC_EXCL:与IPC_CREAT一起使用,如果队列已经存在,则失败。
    • 如果单独使用IPC_CREAT,则msgget()要么返回一个新创建的消息队列的标识符,要么返回具有相同关键字值得队列的标识符。如果IPC_EXCL和IPC_CREAT一起使用,则msgget()要么创建一个新的消息队列,要么如果队列已经存在则返回一个失败值-1.IPC_EXCL单独使用是没有用处的。
      返回说明:
  • 成功执行:返回消息队列标识值。
  • 失败返回-1,errno被设置为以下的某个值。
    + EAXXES: 指定的消息队列已存在,但调用进程没有权限访问它,而且不拥有CAP_IPC_OWNER权能
    + EEXIST: key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志
    + ENOENT: key指定的消息队列不存在同时msgflg中不指定IPC_CREAT标志
    + EENOMEM: 需要建立消息队列,但内存不足
    + ENOSPC: 需要建立消息队列,但已达到系统的最大消息队列容量

fopen()
函数作用:打开指定路径的文件,获取指向该文件的指针
函数原型:FILE* fopen(const char* path, const char* mode)
参数说明:

  • path: 文件路径
  • mode:文件打开方式
    • “rb”:读方式打开一个二进制文件,不允许写数据,文件必须存在
    • ”rb+“:读写打开一个二进制文件,允许读写数据,文件必须存在
    • “r” 以只读方式打开文件,该文件必须存在。
    • “w" 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
    • “w+” 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
    • “a” 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
    • “a+” 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。(原来的EOF符不保留)
    • “wb” 只写打开或新建一个二进制文件,只允许写数据。
      +“wb+” 读写打开或建立一个二进制文件,允许读和写。
    • “ab” 追加打开一个二进制文件,并在文件末尾写数据。
    • "ab+"读写打开一个二进制文件,允许读,或在文件末追加数据。
      返回值:
  • 文件打开成功:返回指向该流得文件指针
  • 文件打开失败:返回NULL,并把错误代码存在errno中

fwrite()函数
函数作用:将一块内存区域中的数据写入到本地文件中
函数原型:size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream)
参数说明:

  • buffer:指向数据块的指针
  • size:每个数据块的大小,单位为byte
  • count:数据个数
  • stream:文件指针

注意:返回值随着调用格式的不同而不同:
(1) 调用格式: fwrite(buf, sizeof(buf), 1, fp)
成功则返回1(count)
(2)调用格式:fwrite(buf, 1,sizeof(buf), fp)
成功则返回实际写入的数据个数(单位为Byte)

注意:写完数据后要调用fclose()关闭流。不关闭流的情况下,每次读或者写数据后,文件指针都会指向下一个待写或者读数据位置


fread()函数
函数作用:从一个文件中读取数据
函数原型: size_t fread(void* buffer, size_t size, size_t count, FILE* stream)
参数说明:

  • buffer:指向数据块的指针
  • size:每个数据的大小,单位为Byte
  • count:数据个数
  • stream:文件指针

注意:返回值随着调用格式的不同而不同:
(1) 调用格式:fread(buf,sizeof(buf),1,fp);
读取成功时:当读取的数据量正好是sizeof(buf)个Byte时,返回值为1(即count)
否则返回值为0(读取数据量小于sizeof(buf))
(2)调用格式:fread(buf,1,sizeof(buf),fp);
读取成功返回值为实际读回的数据个数(单位为Byte)


fclose()函数
函数作用:关闭流stream,刷新所有的缓冲区

使用fclose()函数就可以将缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。
函数原型: int fclose(FILE* stream)
参数说明:

  • stream:这是只想FILE对象的指针,该FILE对象指定了要被关闭的流
    返回值:
  • 流关闭成功,则返回0
  • 流关闭失败,则返回EOF(-1)

msgctl()函数
函数作用:对msqid标识的消息队列执行cmd操作列,可以直接控制消息队列的行为。
函数说明:
定义在<sys/msg.h>中
函数原型:int msgctl(int msqid, int cmd, struct msqiu_ds* buf)
参数说明:
msqid_ds结构:对于每个队列都有一个msqid_ds来描述队列当前的状态,结构定义如下:

struct msqid_ds {//Linux系统中的定义
struct ipc_perm msg_perm; /* Ownership and permissions
time_t msg_stime; /* Time of last msgsnd() */
time_t msg_rtime; /* Time of last msgrcv() */
time_t msg_ctime; /* Time of last change */
unsigned long __msg_cbytes; /* Current number of bytes inqueue (non-standard) */
msgqnum_t msg_qnum; /* Current number of messagesin queue */
msglen_t msg_qbytes; /* Maximum number of bytesallowed in queue */
pid_t msg_lspid; /* PID of last msgsnd() */
pid_t msg_lrpid; /* PID of last msgrcv() */
};//不同的系统中此结构会有不同的新成员

cmd:

  • IPC_STAT:读取消息队列的数据结构msqid_ds,并将其储存在buf指定的地址中
  • IPC_SET:设置消息队列的数据结构msqid_ds中的ipc_perm元素的值。这个值取自buf参数
  • IPC_RMID:从系统内核中移走消息队列
    头文件:
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>

返回值说明:

  • 成功返回0
  • 失败返回-1,错误信息存在errno中
    • EACCES:没有读的权限同时cmd是IPC_STAT
    • EFAULT:buf指向的地址无效
    • EIDRM:在读取中队列被删除
    • EINVAL:msgqid无效,或者msgsz小于0
    • EPERM:IPC_SET或者IPC_RMID命令被使用,但调用程序没有写的权限

feof()函数
函数作用:检测流上的文件结束符

  • 如果文件结束,则返回非0值
  • 文件未结束,则返回0
    文件结束符只能被clearerr()清除
    函数原型:int feof(FILE* stream)
    参数说明:
  • stream:FILE结构的指针

注意:feof判断文件是通过读取函数fread/fcanf等返回错误来识别的,故判断文件是否结束应该是在读取函数之后进行判断。比如:在while循环中读取一个文件时,如果实在读取函数之前进行判断,则如果文件最后一行是空白行,可能会造成内存错误


fscanf()函数
函数作用:从流stream读取格式化输入
函数原型:int fscanf(FILE* stream, const char* format,......)
参数说明:

  • stream:指向FILE对象的指针,该FILE对象标识了流
  • format:这是C字符串,包含了一下各项中的一个或多个:空格字符,非空格字符和format说明符。format说明符格式为:[=%[*][width][modifiers]type=]
    参数说明:
参数 描述
* 这是一个可选的星号,表示数据是从流stream中读取的,但是可以被忽略,即它不储存在对应的参数中
width 这指定了在当前读取操作中读取的最大字符数。
modifiers 为对应的附加参数所指向的数据指定一个不同于整型(针对 d、i 和 n)、无符号整型(针对 o、u 和 x)或浮点型(针对 e、f 和 g)的大小: h :短整型(针对 d、i 和 n),或无符号短整型(针对 o、u 和 x) l :长整型(针对 d、i 和 n),或无符号长整型(针对 o、u 和 x),或双精度型(针对 e、f 和 g) L :长双精度型(针对 e、f 和 g)
type 一个字符,指定了要被读取的数据类型以及数据读取方式。具体参见下一个表格
类型 合格的输入 参数的类型
c 单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符。 char*
d 十进制整数:数字前面的 + 或 - 号是可选的。 int*
e,E,f,g,G 浮点数:包含了一个小数点、一个可选的前置符号 + 或 -、一个可选的后置字符 e 或 E,以及一个十进制数字。两个有效的实例 -732.103 和 7.12e4 float*
o 八进制整数 int*
s 字符串。这将读取连续字符,直到遇到一个空格字符(空格字符可以是空白、换行和制表符)。 char*
u 无符号的十进制整数。 unsigned int*
x,X 十六进制整数。 int*
  • 附加参数:根据不同的format字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了format参数中指定的每个%标签。参数个数应与%标签的个数相同
    返回值:
  • 如果成功,该函数返回成功匹配和赋值的个数。
  • 如果到达文件末尾或发生读错误,则返回 EOF。

msgsnd()函数
函数作用:用来向消息队列发送消息
函数说明:
函数定义在<sys/msg.h>
函数原型:int msgsnd(int msqid, struct msgbuf* msgp, int msgsz, int msgflg)
参数说明:

  • msqid:消息队列对象标识符(由msgget()函数得到)
  • msgp:指向要发送的消息所在的内存
  • msgsz:要发送信息的长度(单位是Byte)
  • msgflg:控制函数行为的标志,可以取以下的值:
    • 0,忽略标志位;
    • IPC_NOWAIT,如果消息队列已满,消息将不被写入队列,控制权返回调用函数的线程。如果不指定这个参数,线程将被阻塞直到消息被可以被写入。

msgrcv()函数
函数作用:用来从消息队列中取出消息
定义在<sys/msg.h>中
函数原型:int msgrcv(int msqid, struct msgbuf* msgp, int msgsz, long mtype, int msgflg)
参数说明:

  • msqid:消息队列对象标识符(由msgget()函数得到)
  • msgp:指向要发送的消息所在的内存
  • msgsz:要发送信息的长度(单位是Byte)
  • mtype:指定了函数从队列中所取的消息的类型
    • 0:收到的第一条信息,任意类型
    • 0:收到的第一条msgtype类型的消息

    • 《0:收到的第一条最低类型(小于或等于msgtype的绝对值的)消息

函数将从队列中搜索类型与之匹配的消息并将之返回。不过有一个例外:如果mtype的值是0的话,函数将不做类型检查而自动返回队列中的醉酒的消息

  • msgflg:控制函数行为的标志

    • 0,表示忽略
    • IPC_NOWAIT :如果消息队列为空,则返回一个ENOMSG,并将控制权交回调用函数的进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件的消息为止。如果一个client正在等待消息的时候队列被删除,EIDRM就会被返回。如果进程在阻塞等待过程中收到了系统的中断信号,EINTR就会被返回。
    • MSG_NOERROR:如果函数取得的消息长度大于msgsz,将之返回msgsz长度的信息,剩下的部分被丢弃了。如果不指定这个参数,E2BIG将被返回,而消息则留在队列中不被取出,当消息从队列内取出后,相应的消息就从队列中删除了。

atol()函数
函数功能:将指向的字符串转换为一个长整数
函数原型:long int atol(const char* str)
参数说明:str:要转换成长整数的字符串
返回值:

  • 成功则返回转换后的长整数
  • 如果失败,则返回0
函数原理性解释:

 总共有两个主要的程序:发送程序和接收程序;

  • 发送程序:先创建一个消息队列对象,然后打开已经保存好的txt文件,将文件中的信息一行一行地读到buffer中,再将其存放到消息队列中。如此循环,直到txt文件中的数据全部读取完毕。
  • 接收程序:打开消息队列(不创建新的消息队列),然后根据msgtype取出消息队列的数据,直到读完所有该类型的停止。另外,最后会检查消息队列是否已空,若是则会询问是否要删除该消息队列,否则直接退出。
  • 进程间通信的方式就是:创建了一个消息队列,然后发送进程往队列中传输数据,接收进程负责将数据从队列中取出来。
函数实现细节解释:


发送程序:


接收进程:


运行结果:

修改代码,使其并发运行并观察消息队列的变化情况

原理性解释:

一共创建了两个程序:

控制台来创建并回收消息队列,发送进程的信息来源于键盘输入。

控制程序只负责创建并回收消息队列。
并发进程:不需要再创建一个新的消息队列,只需要在进程中创建一个消息队列对象,然后在一个死循环中,每次开始时就询问是要进行什么样的操作:
printf("What kind of service you want? 0->send 1->recv 2->exit\n");
当用户输入0时,开始向消息队列进行发送数据

 if(service == 0){printf("Please input the type of the message:\n");fgets(buffer, BUFSIZ, stdin);msgtype = atoi(buffer);printf("Please input the message:\n");fgets(buffer, BUFSIZ, stdin);printf("%ld %s\n", msgtype, buffer);                  data.msg_type = msgtype;                              strcpy(data.mtext, buffer);ret = msgsnd(msqid, (void *)&data, TEXT_SIZE, 0); /* 0: blocking send, waiting when msg queue is full */if(ret == -1) {printf("Msg is full already!\n");}

注意:当消息队列已满时,无法继续进行发送。
当用户输入0时,从消息队列中取出数据

 if(service == 0){printf("Please input the type of the message:\n");fgets(buffer, BUFSIZ, stdin);msgtype = atoi(buffer);printf("Please input the message:\n");fgets(buffer, BUFSIZ, stdin);printf("%ld %s\n", msgtype, buffer);                  data.msg_type = msgtype;                              strcpy(data.mtext, buffer);ret = msgsnd(msqid, (void *)&data, TEXT_SIZE, 0); /* 0: blocking send, waiting when msg queue is full */if(ret == -1) {printf("Msg is full already!\n");}

注意:当消息队列已空时无法再从消息队列中取出消息
当用户输入2时,退出
直接break退出循环即可

细节解释:


并发进程:



运行结果:

创建两个并发进程:

在一个终端中连续发送三次消息:

在另一个终端中连续将三个信息取出:

再想从消息队列取出时,输出警告:

退出进程后:
选择删除消息队列:


代码:
控制程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>#include "alg.9-0-msgdata.h"int main(int argc, char *argv[])
{char pathname[80];struct stat fileattr;key_t key;int msqid, ret;if(argc < 2) {printf("Usage: ./a.out pathname\n");return EXIT_FAILURE;}strcpy(pathname, argv[1]);if(stat(pathname, &fileattr) == -1) {ret = creat(pathname, O_RDWR);if (ret == -1) {ERR_EXIT("creat()");}printf("shared file object created\n");}key = ftok(pathname, 0x27); /* project_id can be any nonzero integer */if(key < 0) {ERR_EXIT("ftok()");}printf("\nIPC key = 0x%x\n", key); msqid = msgget((key_t)key, 0666 | IPC_CREAT);        //控制台先创建一个消息队列,并发程序就能直接访问       if(msqid == -1) {ERR_EXIT("msgget()");}printf("do you want to delete this msg queue?(y/n)");if(getchar() == 'y') {if(msgctl(msqid, IPC_RMID, 0) == -1)perror("msgctl(IPC_RMID)");}system("ipcs -q");exit(EXIT_SUCCESS);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/stat.h>#include "alg.9-0-msgdata.h" int main(int argc, char *argv[]) /* Usage: ./b.out pathname  */
{key_t key;struct stat fileattr;char pathname[80];int msqid, ret;struct msg_struct data;long int msgtype = 0;   /* 0 - type of any messages */              int service;char buffer[BUFSIZ + 1];if(argc < 2) {printf("Usage: ./b.out pathname msg_type\n");return EXIT_FAILURE;}strcpy(pathname, argv[1]);if(stat(pathname, &fileattr) == -1) {ERR_EXIT("shared file object stat error");}if((key = ftok(pathname, 0x27)) < 0) {ERR_EXIT("ftok()");}printf("\nIPC key = 0x%x\n", key);//    msqid = msgget((key_t)key, 0666 | IPC_CREAT);msqid = msgget((key_t)key, 0666); /* do not create a new msg queue */if(msqid == -1) {ERR_EXIT("msgget()");}while(1){printf("What kind of service you want? 0->send 1->recv 2->exit\n");fgets(buffer, BUFSIZ, stdin);service = atoi(buffer);if(service == 0){printf("Please input the type of the message:\n");fgets(buffer, BUFSIZ, stdin);msgtype = atoi(buffer);printf("Please input the message:\n");fgets(buffer, BUFSIZ, stdin);printf("%ld %s\n", msgtype, buffer);                  data.msg_type = msgtype;                              strcpy(data.mtext, buffer);ret = msgsnd(msqid, (void *)&data, TEXT_SIZE, 0); /* 0: blocking send, waiting when msg queue is full */if(ret == -1) {printf("Msg is full already!\n");}}else if(service == 1){printf("Please input the type of the message:(0->recvall)\n" );fgets(buffer, BUFSIZ, stdin);msgtype = atoi(buffer);ret = msgrcv(msqid, (void *)&data, TEXT_SIZE, msgtype, IPC_NOWAIT); /* Non_blocking receive */if(ret == -1) { /* end of this msgtype */printf("Msg is empty!\n");continue;}printf("%ld %s\n", data.msg_type, data.mtext);}else if(service == 2){break;}}struct msqid_ds msqattr;ret = msgctl(msqid, IPC_STAT, &msqattr);printf("number of messages remainding = %ld\n", msqattr.msg_qnum); system("ipcs -q");exit(EXIT_SUCCESS);
}

仿照alg.8-4~8-6,编制基于POSIX API的进程间消息发送和消息接收例程

mq_open()函数
函数作用:用于打开或创建一个消息队列
函数原型:mqd_t mq_open(const char* name, int oflag, mode_t mode, struct mq_attr* attr)
参数说明:

  • name:消息队列的名字
  • oflag:打开方式。有必须的选项:O_RDONLY,O_WRONLY,O_RDWR,还有可选的选项:O_NONBLOCK,O_CREAT,O_EXCL。
  • mode:是一个可选参数,在oflag中含有O_CREAT标志且消息队列不存在时,才需要提供该参数。表示默认访问权限。
  • attr:也是一个可选参数,在oflag中含有O_CREAT标志且消息队列不存在时才需要。该参数用于给新队列设定某些属性,如果是空指针,那么就采用默认属性。
    返回值:
  • 创建成功,返回mqd_t类型的值,称为消息队列描述符。
  • 创建失败,返回一个负值

mq_close()函数
函数作用:用于关闭一个消息队列。关闭后,消息队列并不会从系统中删除。一个进程结束,会自动调用关闭打开着的消息队列
函数原型:mqd_t mq_close(mqd_t mqdes)
参数说明:

  • mqdes:消息队列描述符,由mq_open()函数产生
    返回值:
  • 函数执行成功,返回0
  • 执行失败,返回-1,并设置errno。

mq_unlink()函数
函数作用:销毁一个消息队列,如果该消息队列已经被一个进程打开,则消息队列的销毁会被推迟到所有的引用都被关闭时执行。
函数原型:int mq_unlink(const char *name)
参数说明:

  • name:消息队列描述符
    返回值:
  • 执行成功:返回0
  • 执行失败,返回-1,并设置errno

mq_send()函数
函数作用:将消息发送到消息队列中
函数原型:int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len,unsigned msg_prio);
函数描述:mq_send()会将参数msg_ptr指向的内容发送给参数mqdes指向的消息队列。msg_len指定消息的大小,其不应该大于消息队列的属性mq_msgsize的值,否则函数执行失败
参数说明:

  • mqdes:消息队列描述符
  • msg_ptr:指向消息结构体的指针
  • msg_len:消息的字节数,不得大于mq_msgsize
  • msg_prio:消息的优先级,优先级大的会插队在优先级小的消息前面
    返回值:
  • 成功返回0
  • 失败返回-1,滨水共和制errno

mq_receive()函数
函数原型:ssize_t mq receive(mqd_t mqdes, char* msg_ptr, size_T msg_len, unsigned* msg_prio);
函数说明:mq_receive()会将mqdes指定的消息队列中取出最高优先级排队时间最久的消息,如果msg_len比消息队列的属性mq_msgsize小,函数执行失败。
参数说明:

  • mqdes:消息队列的描述符
  • msg_ptr:指向消息结构体的指针
  • msg_len:消息的字节数
  • msg_prio:指向要保存消息优先级的内存
    返回值:
  • 成功返回0
  • 失败返回-1,并设置errno

需要注意以下几点:
1、消息队列的名字只能以一个 ‘/‘开头,名字中不能包含其他的’/’
2、mq_receive() 的第三个参数表示读取消息的长度,不能小于能写入队列中消息的最大大小,即一定要大于等于该队列的 mq_attr 结构中 mq_msgsize 的大小。
3、消息的优先级:它是一个小于 MQ_PRIO_MAX 的数,数值越大,优先级越高。 POSIX 消息队列在调用 mq_receive 时总是返回队列中最高优先级的最早消息。如果消息不需要设定优先级,那么可以在 mq_send 是置 msg_prio 为 0, mq_receive 的 msg_prio 置为 NULL。
4、默认情况下mq_send和mq_receive是阻塞进行调用,可以通过mq_setattr来设置为O_NONBLOCK,如:
struct mq_attr new_attr;
mq_getattr(mqID, &new_attr);//获取当前属性
new_attr.mq_flags = O_NONBLOCK;//设置为非阻塞
mq_setattr(mqID, &new_attr, NULL)//设置属性

实现原理

实现包含两个程序:控制程序和并发程序:

  • 控制程序:用于创建并回收消息队列
  • 并发程序:用于提供消息发送和接收服务------在终端下选择要进行的操作
细节解释

控制进程:

服务进程:


运行结果:


代码:
控制台代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mqueue.h>
#include <sys/wait.h>#include "alg.9-0-msgdata.h"int main(int argc, char* argv[])
{   mqd_t mqID;mqID = mq_open("/anonymQueue", O_RDWR | O_CREAT , 0666, NULL);if (mqID < 0){ERR_EXIT("con: mq_open()");}printf("do you want to stop IPC? y -> stop:\n");if(getchar() == 'y') {if(mq_unlink("/anonymQueue") == -1)ERR_EXIT("con: unlink()");}system("ipcs -q");   return EXIT_SUCCESS;
}

服务进程代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mqueue.h>#include "alg.9-0-msgdata.h"int main(int argc, char *argv[])
{mqd_t mqID;long int msgtype;char buffer[BUFSIZ + 1];struct msg_struct data;int service;struct mq_attr mqAttr;int ret;unsigned int prio;mqID = mq_open("/anonymQueue", O_RDWR | O_CREAT, 0666,NULL); /* /dev/shm/filename as the shared object */if(mqID == -1) {ERR_EXIT("producer: mq_open()");} mq_getattr(mqID,&mqAttr);while(1){printf("What kind of service you want?input 0 -> send 1->receive 2->exit\n");fgets(buffer, BUFSIZ, stdin);service = atoi(buffer);if(service == 0){printf("Please input the type of the message:\n");fgets(buffer, BUFSIZ, stdin);msgtype = atoi(buffer);printf("Please input the message:\n");fgets(buffer, BUFSIZ, stdin);printf("%ld %s\n", msgtype, buffer);                  data.msg_type = msgtype;                              strcpy(data.mtext, buffer);ret = mq_send(mqID, data.mtext,sizeof(data),0);if(ret == -1){printf("The Queue is full!\n");}}else if(service == 1){printf("Please input the type of the message:(0->recvall)\n" );fgets(buffer, BUFSIZ, stdin);prio = atoi(buffer);ret = mq_receive(mqID, buffer,mqAttr.mq_msgsize,NULL); /* Non_blocking receive */if(ret == -1) { /* end of this msgtype */printf("The MsgQueue is empty!\n");continue;}printf("%s",buffer);}else if(service == 2){break;}}return EXIT_SUCCESS;
}

进程间通信-消息机制相关推荐

  1. 操作系统实验报告8:进程间通信—消息机制

    操作系统实验报告8 实验内容 实验内容1:进程间通信-消息机制 编译运行课件 Lecture 09 例程代码: Algorithms 9-1 ~ 9-2. 修改代码,观察在 msgsnd 和 msgr ...

  2. windows程序消息机制(Winform界面更新有关)--转

    1. Windows程序消息机制 Windows GUI程序是基于消息机制的,有个主线程维护着消息泵.这个消息泵让windows程序生生不息. Windows程序有个消息队列,窗体上的所有消息是这个队 ...

  3. Linux的进程间通信-消息队列

    Linux的进程间通信-消息队列 微博ID:orroz 微信公众号:Linux系统技术 前言 Linux系统给我们提供了一种可以发送格式化数据流的通信手段,这就是消息队列.使用消息队列无疑在某些场景的 ...

  4. 《Android开发艺术探索》读书笔记 (10) 第10章 Android的消息机制

    第10章 Android的消息机制 10.1 Android消息机制概述 (1)Android的消息机制主要是指Handler的运行机制,其底层需要MessageQueue和Looper的支撑.Mes ...

  5. windows程序消息机制(Winform界面更新有关)

    1. Windows程序消息机制 Windows GUI程序是基于消息机制的,有个主线程维护着消息泵.这个消息泵让windows程序生生不息. Windows程序有个消息队列,窗体上的所有消息是这个队 ...

  6. Android 开发艺术探索——第十章 Android的消息机制

    Android 开发艺术探索--第十章 Android的消息机制读书笔记 Handler并不是专门用于更新UI的,只是常被用来更新UI 概述 Android的消息机制主要值得就是Handler的运行机 ...

  7. 【学习】Android的消息机制

    Android的消息机制主要指Handler的运行机制,而Handler的运行需要MessageQueue和Looper支撑 前置知识 MessageQueue:消息队列,内部以单链表的形式存储消息列 ...

  8. 【Android】线程间通信——Handler消息机制

    文章目录 引言 Java层 永动机跑起来 示例 Looper Handler MessageQueue 永动机停下 Native层 nativeInit() nativePollOnce() nati ...

  9. Android消息机制学习笔记

    Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑: MessageQueue:消息队列,它的内存存储了一组消息,以队 ...

  10. WPF的消息机制(二)- WPF内部的5个窗口之隐藏消息窗口

    原文:WPF的消息机制(二)- WPF内部的5个窗口之隐藏消息窗口 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/powertoolsteam/ar ...

最新文章

  1. 下推自动机详讲 包含Java实现 Pushdown Automata (PDA)
  2. php操作xml文件,php xml文件操作代码(一)
  3. android小知识之意图(intent)
  4. 标准库类型string的基本功能和使用
  5. 机器学习中的数学知识(part2)
  6. PYPL 7月榜单公布:Java份额出现下降趋势
  7. oracle客户端三种连接,客户端连接ORACLE的几种方法
  8. 小米5x对标OV,突围荣耀,能否成功?
  9. 每日算法系列【LeetCode 330】按要求补齐数组
  10. 学习ARM64页表转换流程
  11. js 判断对象数组是否存在某一个对象(全)
  12. c语言做图书销售管理系统,C语言图书销售管理系统(38页)-原创力文档
  13. 视频存储空间计算公式
  14. 计算机硬件检测与维修理论试题,计算机硬件检测与维修试题10.doc
  15. tail -f和tail -F的区别
  16. 个人和企业如何注册腾讯云账号?
  17. 三本 计算机专业,四川哪些三本大学的计算机专业最好?
  18. android+客户端+教程,Android新浪客户端开发教程完整版.pdf
  19. python安装Chrome插件
  20. 蜂鸟E203图像识别--未完待续

热门文章

  1. 使用VMWARE(VMware8)安装Mac OSX 雪豹操作系统
  2. 苹果雪豹操作系统正式版_苹果放出iOS 13andiPadOS beta 2:加入SMB网络共享、APFS硬盘支持...
  3. python爬虫用AI技术-破解企业工商数据抓取+网络爬虫+网站数据采集+数据抓取遇到的三大问题
  4. 一元四次方程的求根公式
  5. 小觅双目相机如何使用_小觅双目相机测试
  6. 什么是视频分配器 编码器
  7. python画鱼骨图_这样做数据可视化驾驶舱,高端大气,一目了然,领导不点赞都难...
  8. UMLChina公众号文章精选(20220807更新精选)
  9. mysql用拼音显示字段名_MySQL汉字字段按拼音排序显示
  10. 外文文献找不到怎么办?