进程地消息通信带问题详解版Word文档下载推荐.docx
《进程地消息通信带问题详解版Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《进程地消息通信带问题详解版Word文档下载推荐.docx(14页珍藏版)》请在冰豆网上搜索。
5.实验环境(硬件环境、软件环境):
(1)硬件环境:
IntelPentiumIII以上CPU,128MB以上存,2GB以上硬盘
(2)软件环境:
linux操作系统。
6.预备知识
(1)msgget()系统调用:
头文件#include<
sys/msg.h>
函数原型intmsgget(key_tkey,intflag);
功能:
创建消息队列,或返回与key对应的队列描述符。
成功返回消息描述符,失败则返回-1。
参数:
key是通信双方约定的队列关键字,为长整型数。
flag是访问控制命令,它的低9位为访问权限(代表用户、组用户、其他用户的读、写、执行访问权),其它位为队列建立方式。
(例:
rwxrwx---:
111111000)
(2)msgsnd()系统调用:
函数原型intmsgsnd(intid,structmsgbuf*msgp,intsize,intflag);
发送一个消息。
成功返回0,失败返回-1。
id是队列描述符。
msgp是用户定义的缓冲区。
size是消息长度。
flag是操作行为,若(flag&
IPC_NOWAIT)为真,调用进程立即返回;
若(flag&
IPC_NOWAIT)为假,调用进程阻塞,直到消息被发送出去或队列描述符被删除或收到中断信号为止。
缓冲区结构定义如下:
structmsgbuf{longmtype;
charmtext[n];
};
(3)msgrcv()系统调用:
函数原型intmsgrcv(intid,structmsgbuf*msgp,intsize,inttype,intflag);
接收一个消息。
成功返回消息正文长度,失败返回-1。
size是要接收的消息长度。
type是消息类型,若type为0则接收队列中的第一个消息,若type为正则接收类型为type的第一个消息。
flag是操作行为,若(flag&
IPC_NOWAIT)为真,调用进程立即返回。
IPC_NOWAIT)为假,调用进程睡眠,直到接收到消息为止。
(4)msgctl()系统调用:
函数原型intmsgctl(intid,intcmd,structmsgid_ds*buf);
查询消息队列描述符状态,或设置描述符状态,或删除描述符。
cmd是命令类型,若cmd为IPC_STAT,队列id的消息队列头结构读入buf中;
若cmd为IPC_SET,把buf所指向的信息复制到id的消息队列头结构中。
若cmd为IPC_RMID,删除id的消息队列。
Buf为消息队列头结构msgid_ds指针。
(linuxIPC
wenku.baidu./link?
url=NtXNw0BBI7lTg09Gt7Vy_IrwPRP0XyD5n1-s3ZQV-gP7iHN_ndEBOnrA5fYVNOA3wGqnwoahUWnBNkHUeQUrzIdSIsg8uiV0DWlZFHzOn4K)
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<
stdio.h>
sys/types.h>
sys/ipc.h>
#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*/
(server%d)received.\n"
msg.mtype);
}while(msg.mtype!
=1);
/*消息类型为1时,释放队列*/
msgctl(msgqid,IPC_RMID,0);
/*删除消息队列*/
voidmain()
while((i=fork())==-1);
/*创建子进程;
如果创建失败,执行空语句*/
if(!
i)Server();
/*如果i=0,在子进程中,运行Server*/
else/*否则,在父进程中*/
{while((i=fork())==-1);
/*继续创建子进程*/
i)Client();
/*如果i=0,在子进程中,运行Client*/
wait(0);
/*等待子进程结束*/
/*等待子进程结束*/
注:
IPC进程间通信(Inter-ProcessCommunication)就是指多个进程之间相互通信,交换信息的方法。
.cnblogs./liugf05/archive/2012/07/05/2578356.html
(3)上机操作
创建msg.c源文件,编译gcc–omsgmsg.c,运行./msg
观察屏幕,记录结果。
简答:
程序中有,sleep
(1);
比较加上这一句和不加这一句的结果*/,试分析为什么会有这样的运行结果差异。
(4)课堂练习
(1)修改上述程序,让Client向Server发送一个字符串“Themessagehereisjustajoke.”。
Server收到消息后打印出来。
参考答案:
//msg2.c
charmtext[1024];
{msg.mtype=1;
strcpy(msg.mtext,"
Themessagehereisjustajoke."
);
printf("
(client1)sent.\n"
msg,strlen(msg.mtext),0);
/*发送消息msg到msgqid消息队列,可以先把消息正文放到msg.mtext中,strlen(msg.mtext)*/
msgrcv(msgqid,&
msg,1024,0,0);
(server1)received.\n"
%s\n"
msg.mtext);
msgctl(msgqid,IPC_RMID,0);
exit(0);
/*创建子进程*/
/*子进程Server*/
else
/*子进程Client*/
(5)思考:
1、进程的消息传递机制和全局变量是一个概念吗?
消息是通过全局变量进行传递的吗?
{printf("
starcopy\n"
endcopy\n"
{
stardisplay\n"
done!
1.在client里面改变了msg.mtext,但是server里面printf出来却什么也没有,说明全局变量不可在进程间传递信息。
{sleep
(1);
clientrunning!
\n"
sleep
(2);
{
inti;
2.在主函数里面改变全局变量是可以传递消息的,因为这是父进程,server是子进程,子进程继承父进程的全部代码和资源。
3.换个位置又不行了哦,想想是为什么!
有没有晕了呢!
i){
Client();
}/*子进程Client*/
简单的说,不同的进程使用的存空间是不共用的,全局变量只是在同一个进程所占用的存空间中是全局变量,而其他的进程空间是根本看不到这个变量的。
父子进程不共享数据空间、堆、和栈。
所以不存在共享全局变量。
进程间只能IPC。
2、修改上述程序,让Client向Server发送两个字符串“Themessagehereisjustajoke.”。
效果图如下。
{msgqid=msgget(MSGKEY,0777);
//消息1发送
msg.mtype=1;
Thankyou."
//消息2发送
msg.mtype=2;
(client2)sent.\n"
//接收消息1
msg,1024,1,0);
//接收消息2
msg,1024,2,0);
(server2)received.\n"
/*消息类型为2时,释放队列*/