170 likes | 361 Views
进程通信. 中科大软件学院. 消息队列. 消息队列提供了一种 由一个进程向另一个进程发送块数据的方法 。另外,每一个数据块被看作有一个类型,而接收进程可以独立接收具有不同类型的数据块。 消息队列定义如下: #include <sys/msg.h> int msgget (key_t key, int msgflg); int msgrcv (int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
E N D
进程通信 中科大软件学院
消息队列 • 消息队列提供了一种由一个进程向另一个进程发送块数据的方法。另外,每一个数据块被看作有一个类型,而接收进程可以独立接收具有不同类型的数据块。 • 消息队列定义如下: • #include <sys/msg.h> • int msgget(key_t key, int msgflg); • int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg); • int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg); • int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msgget()函数 创建或访问一个消息队列,系统调用msgget()中的第一个参数是关键字值(通常是由ftok()返回的)。这时,打开和存取操作是和参数msgflg中的内容相关的。
msgget()函数 • 实例: • if((key=ftok(".",'a'))==-1){ • perror("ftok"); • exit(1);} • qid=msgget( key, IPC_CREAT | 0666 ); /*创建一个消息队列*/ • if ( qid < 0 ) { /* 创建一个消息队列失败 */ • perror ( "msgget" ); • exit (1) ; • } • printf ("created queue id : %d \n", qid ); /* 输出消息队列的ID */
msgget()函数 • key_t ftok( char * fname, int id ) • fname为指定的文件名 • id为子序号 • 实例: • if((key=ftok(".",'a'))==-1){ • perror("ftok"); • exit(1); • }
msgget()函数 • msgget( key, IPC_CREAT | 0666 ); • 第二位:当前用户的权限:6=110(二进制),每一位分别对应可读,可写,可执行,,6说明当前用户可读可写不可执行 • 第三位:group组用户,6的意义同上 • 第四位:其它用户,每一位的意义同上,0表示不可读不可写也不可执行
读写消息队列 • 系统为这个数据类型提供了两个接口(msgsnd函数,msgrcv函数),分别对应写消息队列及读消息队列。将一个新的消息写入队列,使用函数msgsnd,函数原型如下: • #include <sys/msg.h> • int msgsnd ( int msqid, const void *prt, size_t nbytes, int flags); • int msgrcv ( int msqid, struct msgbuf *ptr, size_t nbytes, long type , int flag);
读写消息队列 • 每个消息都类似如下的数据结构: • struct msgbuf • { • long mtype; • char mtext[1]; • }; • struct msgbuf { long mtype; char mtext[1]; }; • mtype成员代表消息类型,从消息队列中读取消息的一个重要依据就是消息的类型;mtext是消息内容,当然长度不一定为1。因此,对于发送消息来说,首先预置一个msgbuf缓冲区并写入消息类型和内容,调用相应的发送函数即可;对读取消息来说,首先分配这样一个msgbuf缓冲区,然后把消息读入该缓冲区即可。 • 以下为一读取消息队列实例:
发送方: • struct msg{ /*声明消息结构体*/ • long msg_types; /*消息类型成员*/ • char msg_buf[511]; /*消息*/ • }; • int main( void ) { • int qid; • int pid; • int len; • struct msg pmsg; /*一个消息的结构体变量*/ • pmsg.msg_types = getpid(); /*消息类型为当前进程的ID*/ • sprintf (pmsg.msg_buf,"hello!this is :%d\n\0", getpid() ); /*初始化消息*/ • len = strlen ( pmsg.msg_buf ); /*取得消息长度*/ • if ( (qid=msgget(IPC_PRIVATE, IPC_CREAT | 0666)) < 0 ) { /*创建一个消 • 息队列*/ • perror ( "msgget" ); • exit (1) ; • } • if ( (msgsnd(qid, &pmsg, len, 0 )) < 0 ){ /*向消息队列中发送消息*/ • perror ( "msgsn" ); • exit ( 1 ); • } • printf ("successfully send a message to the queue: %d \n", qid); • exit ( 0 ) ; • }
接收方: • struct msg{ /*声明消息结构体*/ • long msg_types; /*消息类型成员*/ • char msg_buf[511]; /*消息*/ • }; • int main( int argc, char * argv[] ) { • int qid; • int len; • struct msg pmsg; • if ( argc != 2 ){ /**/ • perror ( "USAGE: read_msg <queue ID>" ); • exit ( 1 ); • } • qid = atoi ( argv[1] ); /*从命令行中获得消息队列的ID*/
/*从指定队列读取消息 */ • len = msgrcv ( qid, &pmsg, BUFSZ, 0, 0 ); • if ( len > 0 ){ • pmsg.msg_buf[len] = '\0'; /*为消息添加结束符*/ • printf ("reading queue id :%05ld\n", qid ); /*输出队列ID*/ • /*该消息类型就是发送消息的进程ID*/ • printf ("message type : %05ld\n", pmsg.msg_types ); • printf ("message length : %d bytes\n", len ); /*消息长度*/ • printf ("mesage text: %s\n", pmsg.msg_buf); /*消息内容*/ • } • else if ( len == 0 ) • printf ("have no message from queue %d\n", qid ); • else { • perror ( "msgrcv"); • exit (1); • } • system("ipcs -q") ; • exit ( 0 ) ; • }
msgctl()函数 • 函数msgctl可以在队列上做多种操作,函数原型如下: • #include <sys/msg.h> • int msgctl( int msqid, int cmd , struct msqid_ds *buf ); • 参数msqid为指定的要操作的队列,cmd参数指定所要进行的操作,其中有些操作需要buf参数。cmd参数的详细取值及操作如下:
msgctl()函数 • 删除消息队列: • int main ( int argc ,char *argv[] ) • { • int qid ; • if ( argc != 2 ){ /* 命令行参数出错 */ • puts ( "USAGE: del_msgq.c <queue ID >" ); • exit ( 1 ); • } • qid = atoi ( argv[1] ); /* 通过命令行参数得到组ID */ • system( "ipcs -q"); • if ( ( msgctl( qid, IPC_RMID, NULL ) ) < 0 ){ /* 删除指定的消息队列 */ • perror ("msgctl"); • exit (1 ); • } • exit( 0 ); • }
实验内容 • 用消息队列实现的简单聊天程序 • 实验报告提交内容: • 1、程序流程图 • 2、程序代码 • 3、运行结果 • 接收作业邮箱:chenbo2008@ustc.edu.cn