资源预览内容
第1页 / 共20页
第2页 / 共20页
第3页 / 共20页
第4页 / 共20页
第5页 / 共20页
第6页 / 共20页
第7页 / 共20页
第8页 / 共20页
第9页 / 共20页
第10页 / 共20页
亲,该文档总共20页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
实验项目四实验项目四 进程通信进程通信一、 实验类型本实验为综合性实验。二、 实验目的1. 了解什么是消息,熟悉消息传送原理。 2. 了解和熟悉共享存储机制。 3. 掌握消息的发送与接收的实现方法。三、 实验预备知识任务一任务一 消息的发送和接收消息的发送和接收1. 实验基本原理消息(message)是一个格式化的可变长的信息单元。消息机制允许由一个进程给其它任意的进程发送一个消息。当一个 进程收到多个消息时,可将它们排成一个消息队列。消息使用两种重要的数据结构:一是消息首部,其中记录了一些与消息 有关的信息,如消息数据的字节数;二是消息队列头表,其每一表项是作为一个消息队列的消息头,记录了消息队列的有关 信息。 消息机制的数据结构: struct msgform long mtype;char mtext1024; ; (1)消息首部 记录一些与消息有关的信息,如消息的类型、大小、指向消息数据区的指针、消息队列的链接指针等。 (2)消息队列头表 其每一项作为一个消息队列的消息头,记录了消息队列的有关信息如指向消息队列中第一个消息和指向最后一个消息的 指针、队列中消息的数目、队列中消息数据的总字节数、队列所允许消息数据的最大字节总数,还有最近一次执行发送操作 的进程标识符和时间、最近一次执行接收操作的进程标识符和时间等。 (3)消息队列的描述符 UNIX 中,每一个消息队列都有一个称为关键字(key)的名字,是由用户指定的;消息队列有一消息队列描述符,其作 用与用户文件描述符一样,也是为了方便用户和系统对消息队列的访问。2. msgget( )函数头文件:头文件: #include #include #include 函数原型:函数原型: int msgget(key_t key, int msgflag); 函数说明:函数说明: 创建一个消息,获得一个消息的描述符。系统内核将搜索消息队列头表,确定是否有指定名字的消息队列。若无,系统 内核将分配一新的消息队列头,并对它进行初始化,然后给用户返回一个消息队列描述符,否则它只是检查消息队列的许可 权便返回。 系统调用格式:msgqid=msgget(key,flag)。其中:msgqid 是该系统调用返回的描述符,失败则返回-1。msgget()函数的第 一个参数是消息队列对象的关键字(key),函数将它与已有的消息队列对象的关键字进行比较来判断消息队列对象是否已经创 建。而函数进行的具体操作是由第二个参数 msgflg 控制的。它可以取下面的几个值: IPC_CREAT :如果消息队列对象不存在,则创建之,否则则进行打开操作; IPC_EXCL:和 IPC_CREAT 一起使用(用”|”连接) ,如果消息对象不存在则创建之,否则产生一个错误并返回。如果单独使用 IPC_CREAT 标志,msgget()函数要么返回一个已经存在的消息队列对象的标识符,要么返回一个新建立 的消息队列对象的标识符。如果将 IPC_CREAT 和 IPC_EXCL 标志一起使用,msgget()将返回一个新建的消息对象的标识符, 或者返回-1。如果消息队列对象已存在,IPC_EXCL 标志本身并没有太大的意义,但和 IPC_CREAT 标志一起使用可以用来 保证所得的消息队列对象是新创建的而不是打开的已有的对象。 除了以上的两个标志以外,在 msgflg 标志中还可以有存取权限控制符。这种控制符的意义和文件系统中的权限控制符是 类似的。3. msgsnd( )函数头文件:头文件: #include #include #include 函数原型:函数原型: int msgsnd(int msqid, const void *msgp, intt msgsz, int msgflg); 函数说明:函数说明: 在消息队列上进行收发消息,为了发送消息,调用进程对消息队列进行写入时必须有写权能。成功执行时返回 0,失败 时返回-1。其中 msgqid 是返回消息队列的描述符;msgp 是指向用户消息缓冲区的一个结构体指针。缓冲区中包括消息类型 和消息正文,即 long mtype; /*消息类型*/char mtext ; /*消息的文本*/ msgsz 指示由 msgp 指向的数据结构中字符数组的长度;即消息的长度。这个数组的最大值由 MSG-MAX( )系统可调用参 数来确定。msgflag 参数是控制函数行为的标志,取值可以是:0,表示忽略。若在标志 msgflag 中未设置 IPC_NOWAIT 位,则当该消息队列中的字节数超过最大值时,或系统范围的消息数超过某一最大值时,调用 msgsnd 进程睡眠。若是设置 IPC_NOWAIT,则在此情况下,msgsnd 立即返回。 对于 msgsnd( ),系统内核须完成以下工作: (1)对消息队列的描述符和许可权及消息长度等进行检查。若合法才继续执行,否则返回; (2)系统内核为消息分配消息数据区。将用户消息缓冲区中的消息正文,拷贝到消息数据区; (3)分配消息首部,并将它链入消息队列的末尾。在消息首部中须填写消息类型、消息大小和指向消息数据区的指针等 数据; (4)修改消息队列头中的数据,如队列中的消息数、字节总数等。最后,唤醒等待消息的进程。4. msgrcv ( )函数头文件:头文件: #include #include #include 函数原型:函数原型: int msgrcv(int msqid, void *msgp, int msgsz, long msgtyp, int msgflg); 函数说明:函数说明: msgrcv ( )函数用来接收一消息。从指定的消息队列中接收指定类型的消息。其中,msgqid,msgp,msgsz,msgflg 与 msgsnd 中的对应参数相似,msgtyp 是规定要读的消息类型,msgflg 规定倘若该队列无消息,系统内核应做的操作,是控制函数行为 的标志,取值可以是:0,表示忽略;IPC_NOWAIT,如果消息队列为空,则返回一个 ENOMSG,并将控制权交回调用函数的 进程。如果不指定这个参数,那么进程将被阻塞直到函数可以从队列中得到符合条件的消息为止。如此时设置了 IPC_NOWAIT 标志,则立即返回,若在 flag 中设置了 MS_NOERROR,且所接收的消息大于 size,则系统内核截断所接收的 消息。 对于 msgrcv 系统调用,系统内核须完成下述工作: (1)对消息队列的描述符和许可权等进行检查。若合法,就往下执行;否则返回; (2)根据 msgtyp 的不同分成三种情况处理: msgtyp=0,接收该队列的第一个消息,并将它返回给调用者;msgtyp 为正整数,接收类型 type 的第一个消息; msgtyp 为负整数,接收小于等于 type 绝对值的最低类型的第一个消息。 (3)当所返回消息大小等于或小于用户的请求时,系统内核便将消息正文拷贝到用户区,并从消息队列中删除此消息, 然后唤醒睡眠的发送进程。但如果消息长度比用户要求的大时,则做出错返回。5. msgctl ( )函数头文件:头文件: #include #include #include 函数原型:函数原型: int msgctl ( int msgqid, int cmd, struct msqid_ds *buf ); 函数说明:函数说明: 系统调用 msgctl ( )用来控制对消息队列的操作。其中,函数调用成功时返回 0,不成功则返回-1。buf 是用户缓冲区地址, 供用户存放控制参数和查询结果;cmd 是规定的命令。命令可分三类: (1)IPC_STAT。查询有关消息队列情况的命令。如查询队列中的消息数目、队列中的最大字节数、最后一个发送消息 的进程标识符、发送时间等; (2)IPC_SET。按 buf 指向的结构中的值,设置和改变有关消息队列属性的命令。如改变消息队列的用户标识符、消息 队列的许可权等; (3)IPC_RMID。消除消息队列的标识符。 msgqid_ds 结构定义如下: struct msgqid_ds struct ipc_perm msg_perm; /*许可权结构*/short pad17; /*由系统使用*/ushort msg_qnum; /*队列上消息数*/ushort msg_qbytes; /*队列上最大字节数*/ushort msg_lspid; /*最后发送消息的 PID*/ushort msg_lrpid; /*最后接收消息的 PID*/time_t msg_stime; /*最后发送消息的时间*/time_t msg_rtime; /*最后接收消息的时间*/time_t msg_ctime; /*最后更改时间*/; struct ipc_perm ushort uid; /*当前用户*/ushort gid; /*当前进程组*/ushort cuid; /*创建用户*/ushort cgid; /*创建进程组*/ushort mode; /*存取许可权*/ short pid1; long pad2; /*由系统使用*/ 6. 样例程序/client_ex.c 发送端 #include #include #include #include #include #define MSGKEY 75 struct msgform long mtype;char mtext1024; msg;int msgqid;void client() msgqid=msgget(MSGKEY,0777); /*打开 75#消息队列*/msg.mtype=1;msg.mtext1=a;printf(“(client)sentn“);msgsnd(msgqid, /*发送消息*/exit(0); int main( ) client( ); /server_ex.c 接收端 #include #include #include #include #include #define MSGKEY 75 struct msgform long mtype;char mtext1024; msg; int msgqid;void server( ) msgqid=msgget(MSGKEY,0777|IPC_CREAT); /*创建 75#消息队列*/msgrcv(msgqid, /*接收消息*/printf(“%c “,msg.mtextmsg.mtype);printf(“(server)receivedn“);msgctl(msgqid,IPC_RMID,0); /*删除消息队列,归还资源*/exit(0); int main( ) server( ); 任务二任务二 使用共享存储区通信使用共享存储区通信1. 实验基本原理共享存储区(Share Memory)是 UNIX 系统中通信速度最高的一种通信机制。该机制可使若干进程共享主存中的某一个 区域,且使该区域出现(映射)在多个进程的虚地址空间中。另一方面,一个进程的虚地址空间中又可连接多个共享存储区, 每个共享存储区都有自己的名字。当进程间欲利用共享存储区进行通信
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号