1、 操作系统实验报告 实验四、进程通信(二) ——消息通信 一、 实验目的 1) 加深对管道通信的了解 2) 掌握利用管道进行通信的程序设计 3) 了解共享内存通信的程序设计方法 4) 了解和熟悉Linux支持的共享存储区机制 二、 实验内容 任务: (1)每个同学登陆两个窗口,先在一个窗口中运行程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),用ipcs命令查看系统中消息队列的情况,然后在另一个窗口中运行程序2,观察程序的运行结果并分析。运行结束后可以用ctrl+c结束程序1的运行,再次用ipcs命令观察系统中消息
2、队列的情况。 (2)使用系统调用msgget(),msgsnd(),msgrev()及msgctl()编制一长度为1K的消息的发送和接收程序。 ①为了便于操作和观察结果,用一个程序作为“引子”,先后fork()两个子进程,SERVER和CLIENT,进行通信。 ②SERVER端建立一个Key为学号末3位的消息队列,等待其他进程发来的消息。当遇到类型为1的消息,则作为结束信号,取消该队列,并退出SERVER。SERVER每接收到一个消息后显示一句“(server)received”。 ③CLIENT端使用key为学号末3位的消息队列,先后发送类型从10到1的消息,然后退出。最后的一个消息
3、即是SERVER端需要的结束信号。CLIENT每发送一条消息后显示一句“(client)sent”。
④父进程在SERVER和CLIENT均退出后结束。
三、 代码及运行结果分析
(1)每个同学登陆两个窗口,先在一个窗口中运行程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),用ipcs命令查看系统中消息队列的情况,然后在另一个窗口中运行程序2,观察程序的运行结果并分析。运行结束后可以用ctrl+c结束程序1的运行,再次用ipcs命令观察系统中消息队列的情况
先在一个窗口中运行程序1
程序1实验代码:
#include
4、
5、i,cleanup); msgqid = msgget (MSGKEY,0777|IPC_CREAT);/*建立与顾客进程相同的消息队列*/ for (;;) { msgrcv (msgqid ,&msg,256,1,0);/*接收来自顾客进程的消息*/ pint=(int * ) msg. mtext; pid = * pint; printf ("server:receive from pid %d\n",pid); msg.mtype=pid; *pint=getpi
6、d();
msgsnd (msgqid,&msg ,sizeof (int) ,0) ;/*发送应答消息*/
}
}
cleanup()
{
msgctl (msgqid ,IPC_RMID,0);
exit();
}
运行结果:
ipcs命令查看
在另一个窗口中运行程序2
程序2实验代码:
#include
7、队列关键字一样而相互干扰,关键字请用学号末3位*/ struct msgform { long mtype; char mtext [256]; }; main() { struct msgform msg; int msgqid,pid, *pint; msgqid=msgget(MSGKEY,0777);/*建立消息队列*/ pid=getpid(); pint=(int *)msg.mtext; *pint=pid; msg.mtype=1;/*指定消息类型*/ msgsnd(msgqid,&msg,sizeof(int),0);/*往msg
8、qid发送消息msg*/ msgrcv(msgqid,&msg,256,pid,0);/*接收来自服务进程的消息*/ printf("client : receive from pid%d\n",*pint); } 运行结果: 再次用ipcs命令观察系统中消息队列的情况 分析: 调用pipe(fd);创建一个管道后,接着调用fork()函数产生两个进程,首先开始执行子进程,关闭管道出口,通过管道入口向管道中写入内容。执行if语句后,进入else语句块内开始父进程,管道入口关闭,通过管道出口端从管道中读取之前写入内容,最后输出出来 (2)使用系统调用msgget(),
9、msgsnd(),msgrev()及msgctl()编制一长度为1K的消息的发送和接收程序。 ①为了便于操作和观察结果,用一个程序作为“引子”,先后fork()两个子进程,SERVER和CLIENT,进行通信。 ②SERVER端建立一个Key为学号末3位的消息队列,等待其他进程发来的消息。当遇到类型为1的消息,则作为结束信号,取消该队列,并退出SERVER。SERVER每接收到一个消息后显示一句“(server)received”。 ③CLIENT端使用key为学号末3位的消息队列,先后发送类型从10到1的消息,然后退出。最后的一个消息,即是SERVER端需要的结束信号。CLIENT每发
10、送一条消息后显示一句“(client)sent”。
④父进程在SERVER和CLIENT均退出后结束。
实验代码:
#include
11、 for(i=10;i>=1;i--) { msg.mtype=i; printf("(client)sent\n"); msgsnd(msgqid,&msg,1024,0); } exit(0); } void SERVER() { msgqid=msgget(MSGKEY ,0777|IPC_CREAT); do { msgrcv(msgqid,&msg,1030,0,0); printf("(server)received\n"); }while(msg.mtype!=1); msgctl(msgqid,IPC_RMID,0); exi
12、t(0); } int main() { while((i=fork())==-1); if(!i)SERVER(); while((i=fork())==-1); if(!i)CLIENT(); wait(0); wait(0); } 运行结果: 分析: msgflg低9位类似于文件访问权限的低9位,其他位指明消息队列的建立方式: 若指定的关键字消息队列不存在,msgflg&IPC_CREAT为真,则为他建立一个新的消息队列; msgflg&IPC_CREAT为假,返回-1。若指定的关键字消息队列存在,则返回该消息队列的描述符。 若msgflg&IP
13、C_CREAT&IPC_EXCL为真,若指定的关键字消息队列不存在,失败返回-1;否则正常返回。 若key等于IPC_PRIVATE,则msgget调用总是成功的。 根据控制命令cmd对msqid消息队列进行相应的控制。参数buf是指向用户程序地址空间中一个msqid_ds结构的指针,以便将相关控制信息在核心和用户地址空间之间进行传送。 四、 实验心得 通过本次实验加深对管道通信的了解,很好的掌握和利用管道进行通信的程序设计,了解共享内存通信的程序设计方法,了解和熟悉Linux支持的共享存储区机制,实验第一个题目较为简单,但当实验进行第二个题目时遇到了一定的问题,说明对于程序编写掌握的还不是特别熟悉,应该加强学。最终通过网络查询和向同学请教得以解决,收获颇多。






