进程的消息通信带答案版.docx
- 文档编号:29778481
- 上传时间:2023-07-26
- 格式:DOCX
- 页数:17
- 大小:101.77KB
进程的消息通信带答案版.docx
《进程的消息通信带答案版.docx》由会员分享,可在线阅读,更多相关《进程的消息通信带答案版.docx(17页珍藏版)》请在冰豆网上搜索。
进程的消息通信带答案版
实验二进程管理
2.2进程的消息通信
1.实验目的
(1)加深对进程通信的理解,理解进程消息传递机制。
(2)掌握进程通信相关系统调用。
(3)理解系统调用和用户命令的区别。
2.实验类型:
验证型
3.实验学时:
2
4.实验原理和知识点
(1)实验原理:
消息通信机制允许进程之间大批量交换数据。
消息通信机制是以消息队列为基础的,消息队列是消息的链表。
发送进程将消息挂入接收进程的消息队列,接收进程从消息队列中接收消息。
消息队列有一个消息描述符。
对消息队列的操作是通过描述符进行的。
任何进程,只要有访问权并且知道描述符,就可以访问消息队列。
每个消息包括一个正长整型的类型字段,和一个非负长度的数据。
进程读或写消息时,要给出消息的类型。
若队列中使用的消息类型为0,则读取队列中的第一个消息。
(2)知识点:
消息、消息队列
5.实验环境(硬件环境、软件环境):
(1)硬件环境:
IntelPentiumIII以上CPU,128MB以上内存,2GB以上硬盘
(2)软件环境:
linux操作系统。
6.预备知识
(1)msgget()系统调用:
头文件#include
函数原型intmsgget(key_tkey,intflag);
功能:
创建消息队列,或返回与key对应的队列描述符。
成功返回消息描述符,失败则返回-1。
参数:
key是通信双方约定的队列关键字,为长整型数。
flag是访问控制命令,它的低9位为访问权限(代表用户、组用户、其他用户的读、写、执行访问权),其它位为队列建立方式。
(例:
rwxrwx---:
111111000)
(2)msgsnd()系统调用:
头文件#include
函数原型intmsgsnd(intid,structmsgbuf*msgp,intsize,intflag);
功能:
发送一个消息。
成功返回0,失败返回-1。
参数:
id是队列描述符。
msgp是用户定义的缓冲区。
size是消息长度。
flag是操作行为,若(flag&IPC_NOWAIT)为真,调用进程立即返回;若(flag&IPC_NOWAIT)为假,调用进程阻塞,直到消息被发送出去或队列描述符被删除或收到中断信号为止。
缓冲区结构定义如下:
structmsgbuf{longmtype;charmtext[n];};
(3)msgrcv()系统调用:
头文件#include
函数原型intmsgrcv(intid,structmsgbuf*msgp,intsize,inttype,intflag);
功能:
接收一个消息。
成功返回消息正文长度,失败返回-1。
参数:
id是队列描述符。
msgp是用户定义的缓冲区。
size是要接收的消息长度。
type是消息类型,若type为0则接收队列中的第一个消息,若type为正则接收类型为type的第一个消息。
flag是操作行为,若(flag&IPC_NOWAIT)为真,调用进程立即返回。
若(flag&IPC_NOWAIT)为假,调用进程睡眠,直到接收到消息为止。
(4)msgctl()系统调用:
头文件#include
函数原型intmsgctl(intid,intcmd,structmsgid_ds*buf);
功能:
查询消息队列描述符状态,或设置描述符状态,或删除描述符。
成功返回0,失败返回-1。
参数:
id是队列描述符。
cmd是命令类型,若cmd为IPC_STAT,队列id的消息队列头结构读入buf中;若cmd为IPC_SET,把buf所指向的信息复制到id的消息队列头结构中。
若cmd为IPC_RMID,删除id的消息队列。
Buf为消息队列头结构msgid_ds指针。
(linuxIPC
7.实验内容及步骤:
(1)任务描述:
使用系统调用msgget()、msgsnd()、msgrcv()、msgctl(),编写消息发送和接收程序。
要求消息的长度为1KB。
(2)程序设计过程:
先定义消息结构,
structmsgbuf{
longmtype;
charmtext[n];
};
用这个结构定义消息缓冲全局变量msg。
定义消息队列描述符msgqid。
约定队列关键字为75。
创建两个子进程client和server。
Client使用msgget()创建消息队列,使用msgsnd()发送10条消息。
Server使用msgget()获取消息队列描述符,然后用msgrcv()接收消息,完毕后删除队列描述符。
为了清楚地显示Client发送的是哪条消息,每发送一条消息,打印消息号(消息类型),Sever每收到一条消息,也打印消息类型。
设计收发方式。
Client每发送一条,Sever就接收一条。
/*收发方式:
Client()每发送一条消息,Server()就接收一条*/
/*此方法不能保证一定能同步。
对于不同速度的机器,如果没有其他耗时的进程,可以调整sleep的时间值而获得同步。
*/
//msg.c
#include
#include
#include
#include
#defineMSGKEY75/*通信双方约定的队列关键字*/
structmsgform/*消息结构*/
{longmtype;/*消息类型*/
charmtext[1030];/*消息正文*/
}msg;
intmsgqid;/*消息队列描述符*/
voidClient()
{inti;/*局部变量i,消息类型(表示第几条消息)*/
msgqid=msgget(MSGKEY,0777);/*创建消息队列,访问权限为777*/
for(i=10;i>=1;i--)
{msg.mtype=i;/*指定消息类型*/
printf("(client%d)sent.\n",i);/*打印消息类型*/
msgsnd(msgqid,&msg,1024,0);
/*发送消息msg到msgqid消息队列,可以先把消息正文放到msg.mtext中*/
sleep
(1);/*使进程挂起1秒。
等待接收进程接收。
比较加上这一句和不加这一句的结果*/
}
exit(0);
}
voidServer()
{/*获得关键字对应的消息队列描述符*/
msgqid=msgget(MSGKEY,0777|IPC_CREAT);
do{
msgrcv(msgqid,&msg,1030,0,0);/*从msgqid队列接收消息msg*/
printf("(server%d)received.\n",msg.mtype);/*打印消息类型*/
}while(msg.mtype!
=1);/*消息类型为1时,释放队列*/
msgctl(msgqid,IPC_RMID,0);/*删除消息队列*/
exit(0);
}
voidmain()
{inti;
while((i=fork())==-1);/*创建子进程;如果创建失败,执行空语句*/
if(!
i)Server();/*如果i=0,在子进程中,运行Server*/
else/*否则,在父进程中*/
{while((i=fork())==-1);/*继续创建子进程*/
if(!
i)Client();/*如果i=0,在子进程中,运行Client*/
}
wait(0);/*等待子进程结束*/
wait(0);/*等待子进程结束*/
}
注:
IPC进程间通信(Inter-ProcessCommunication)就是指多个进程之间相互通信,交换信息的方法。
(3)上机操作
创建msg.c源文件,编译gcc–omsgmsg.c,运行./msg
观察屏幕,记录结果。
简答:
程序中有,sleep
(1);/*使进程挂起1秒。
等待接收进程接收。
比较加上这一句和不加这一句的结果*/,试分析为什么会有这样的运行结果差异。
(4)课堂练习
(1)修改上述程序,让Client向Server发送一个字符串“Themessagehereisjustajoke.”。
Server收到消息后打印出来。
参考答案:
//msg2.c
#include
#include
#include
#include
#defineMSGKEY75/*通信双方约定的队列关键字*/
structmsgform/*消息结构*/
{longmtype;/*消息类型*/
charmtext[1024];/*消息正文*/
}msg;
intmsgqid;/*消息队列描述符*/
voidClient()
{msg.mtype=1;
strcpy(msg.mtext,"Themessagehereisjustajoke.");
msgqid=msgget(MSGKEY,0777);/*创建消息队列,访问权限为777*/
/*指定消息类型*/
printf("(client1)sent.\n");/*打印消息类型*/
msgsnd(msgqid,&msg,strlen(msg.mtext),0);
/*发送消息msg到msgqid消息队列,可以先把消息正文放到msg.mtext中,strlen(msg.mtext)*/
exit(0);
}
voidServer()
{/*获得关键字对应的消息队列描述符*/
msgqid=msgget(MSGKEY,0777|IPC_CREAT);
msgrcv(msgqid,&msg,1024,0,0);/*从msgqid队列接收消息msg*/
printf("(server1)received.\n");/*打印消息类型*/
printf("%s\n",msg.mtext);/*消息类型为1时,释放队列*/
msgctl(msgqid,IPC_RMID,0);/*删除消息队列*/
exit(0);
}
voidmain()
{inti;
while((i=fork())==-1);/*创建子进程*/
if(!
i)Server();/*子进程Server*/
else
{while((i=fork())==-1);/*创建子进程*/
if(!
i)Client();/*子进程Client*/
}
wait(0);/*等待子进程结束*/
wait(0);/*等待子进程结束*/
}
(5)思考:
1、进程的消息传递机制和全局变量是一个概念吗?
消息是通过全局变量进行传递的吗?
//msg2.c
#include
#include
#include
#include
#defineMSGKEY75/*通信双方约定的队列关键字*/
structmsgform/*消息结构*/
{longmtype;/*消息类型*/
charmtext[1024];/*消息正文*/
}msg;
intmsgqid;/*消息队列描述符*/
voidClient()
{printf("starcopy\n");
strcpy(msg.mtext,"Themessagehereisjustajoke.");
printf("endcopy\n");
exit(0);
}
voidServer()
{
sleep
(1);
printf("stardisplay\n");
printf("done!
%s\n",msg.mtext);
printf("endcopy\n");
exit(0);
}
voidmain()
{inti;
while((i=fork())==-1);/*创建子进程*/
if(!
i)Server();/*子进程Server*/
else
{while((i=fork())==-1);/*创建子进程*/
if(!
i)Client();/*子进程Client*/
}
wait(0);/*等待子进程结束*/
wait(0);/*等待子进程结束*/
}
1.在client里面改变了msg.mtext,但是server里面printf出来却什么也没有,说明全局变量不可在进程间传递信息。
//msg2.c
#include
#include
#include
#include
#defineMSGKEY75/*通信双方约定的队列关键字*/
structmsgform/*消息结构*/
{longmtype;/*消息类型*/
charmtext[1024];/*消息正文*/
}msg;
intmsgqid;/*消息队列描述符*/
voidClient()
{sleep
(1);
printf("clientrunning!
\n");
exit(0);
}
voidServer()
{
sleep
(2);
printf("stardisplay\n");
printf("done!
%s\n",msg.mtext);
printf("endcopy\n");
exit(0);
}
voidmain()
{
printf("starcopy\n");
strcpy(msg.mtext,"Themessagehereisjustajoke.");
printf("endcopy\n");
inti;
while((i=fork())==-1);/*创建子进程*/
if(!
i)Server();/*子进程Server*/
else
{while((i=fork())==-1);/*创建子进程*/
if(!
i)Client();/*子进程Client*/
}
wait(0);/*等待子进程结束*/
wait(0);/*等待子进程结束*/
}
2.在主函数里面改变全局变量是可以传递消息的,因为这是父进程,server是子进程,子进程继承父进程的全部代码和资源。
3.换个位置又不行了哦,想想是为什么!
有没有晕了呢!
//msg2.c
#include
#include
#include
#include
#defineMSGKEY75/*通信双方约定的队列关键字*/
structmsgform/*消息结构*/
{longmtype;/*消息类型*/
charmtext[1024];/*消息正文*/
}msg;
intmsgqid;/*消息队列描述符*/
voidClient()
{sleep
(1);
printf("clientrunning!
\n");
exit(0);
}
voidServer()
{
sleep
(2);
printf("stardisplay\n");
printf("done!
%s\n",msg.mtext);
printf("endcopy\n");
exit(0);
}
voidmain()
{
inti;
while((i=fork())==-1);/*创建子进程*/
if(!
i)Server();/*子进程Server*/
else
{while((i=fork())==-1);/*创建子进程*/
if(!
i){
printf("starcopy\n");
strcpy(msg.mtext,"Themessagehereisjustajoke.");
printf("endcopy\n");
Client();}/*子进程Client*/
}
wait(0);/*等待子进程结束*/
wait(0);/*等待子进程结束*/
}
简单的说,不同的进程使用的内存空间是不共用的,全局变量只是在同一个进程所占用的内存空间中是全局变量,而其他的进程空间是根本看不到这个变量的。
父子进程不共享数据空间、堆、和栈。
所以不存在共享全局变量。
进程间只能IPC。
2、修改上述程序,让Client向Server发送两个字符串“Themessagehereisjustajoke.”。
Server收到消息后打印出来。
效果图如下。
//msg2.c
#include
#include
#include
#include
#defineMSGKEY75/*通信双方约定的队列关键字*/
structmsgform/*消息结构*/
{longmtype;/*消息类型*/
charmtext[1024];/*消息正文*/
}msg;
intmsgqid;/*消息队列描述符*/
voidClient()
{msgqid=msgget(MSGKEY,0777);/*创建消息队列,访问权限为777*/
/*指定消息类型*/
//消息1发送
msg.mtype=1;
strcpy(msg.mtext,"Thankyou.");
printf("(client1)sent.\n");/*打印消息类型*/
msgsnd(msgqid,&msg,strlen(msg.mtext),0);
/*发送消息msg到msgqid消息队列,可以先把消息正文放到msg.mtext中,strlen(msg.mtext)*/
//消息2发送
msg.mtype=2;
strcpy(msg.mtext,"Themessagehereisjustajoke.");
printf("(client2)sent.\n");/*打印消息类型*/
msgsnd(msgqid,&msg,strlen(msg.mtext),0);
/*发送消息msg到msgqid消息队列,可以先把消息正文放到msg.mtext中,strlen(msg.mtext)*/
exit(0);
}
voidServer()
{/*获得关键字对应的消息队列描述符*/
msgqid=msgget(MSGKEY,0777|IPC_CREAT);
//接收消息1
msgrcv(msgqid,&msg,1024,1,0);/*从msgqid队列接收消息msg*/
printf("(server1)received.\n");/*打印消息类型*/
printf("%s\n",msg.mtext);/*消息类型为1时,释放队列*/
//接收消息2
msgrcv(msgqid,&msg,1024,2,0);/*从msgqid队列接收消息msg*/
printf("(server2)received.\n");/*打印消息类型*/
printf("%s\n",msg.mtext);/*消息类型为2时,释放队列*/
msgctl(msgqid,IPC_RMID,0);/*删除消息队列*/
exit(0);
}
voidmain()
{inti;
while((i=fork())==-1);/*创建子进程*/
if(!
i)Server();/*子进程Server*/
else
{while((i=fork())==-1);/*创建子进程*/
if(!
i)Client();/*子进程Client*/
}
wait(0);/*等待子进程结束*/
wait(0);/*等待子进程结束*/
}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 进程 消息 通信 答案