模拟进程通信
来源:互联网 发布:知乐作品集txt下载 编辑:程序博客网 时间:2024/05/08 09:09
1,实验要求
2次调用fork创建2个子进程,其中一个充当服务器server,另一个充当客户端client,来模拟操作系统内部进程间的通信。
客户端向服务器消息类型mtype为10到1的消息,服务端接收消息,收到类型为1的消息时则停止接收。
2,进程间通信的主要函数:
/*函数1功能:创建消息队列参数:MSGKEY是一个由用户提供的整数,用来标志这个资源的实例;0777|IPC_CREAT创建消息队列返回:消息队列的id*/msgqid=msgget(MSGKEY,0777|IPC_CREAT);//创建消息队列
/*函数2功能:接收消息参数:msgqid,指定消息队列id;&msg指向放置到来消息的缓冲区;1024限制能够被读到的数据的大小为1024字节,即1K;-10,指定接收消息队列里消息类型小于等于10的最低类型的第一个消息;0,表示消息发送不成功时不立即返回,需要等待。*/msgrcv(msgqid,&msg,1024,-10,0);//接收消息
/*函数3功能:发送消息参数:msgqid,指定消息队列的id;&msg指向放置到来消息的缓冲区;1024指定发送的最大数据量为1024字节,即1K;0,表示消息发送不成功时不立即返回,需要等待。*/msgsnd(msgqid,&msg,1024,0); //发送消息
/*函数4功能:删除消息队列参数:msgqid,指定要删除的消息队列的id;IPC_RMID表示清空并删除消息队列;*/ msgctl(msgqid,IPC_RMID,0);
3 代码实现
/*Name:shiyan4.c *Created on 2015-10-14 *Author:Wanglin *Function:创建两个子进程,模拟服务器和客户端通信 */#include<stdio.h>#include<unistd.h>#include <sys/types.h>#include <sys/msg.h>#include <sys/ipc.h># include<string.h>#define MSGKEY 75struct msgform{ long mtype; //消息首部 char mtext[1024];//1k消息正文} msg;int msgqid;//消息队列id,用来访问消息队列int main(){ int p1,p2; p1=fork();//创建server端 if(!p1) { //[server端] msgqid=msgget(MSGKEY,0777|IPC_CREAT);//由server端创建消息队列 do { msgrcv(msgqid,&msg,1024,-10,0);//server端接收消息 printf("i=%d server:received\n",msg.mtype);//提示server端已接收 msg.mtype=1000;//为了区别应答消息与客户端发送的消息,修改应答消息类型为1000(只要不是1-10即可) msgsnd(msgqid,&msg,1024,0); /*发送应答消息msg*/ } while(msg.mtype!=1); msgctl(msgqid,IPC_RMID,0);//清空并删除消息队列 } else { p2=fork();//创建lient端 if(!p2) { //[client端] int i; msgqid=msgget(MSGKEY,0777|IPC_CREAT);//系统检测到MSGKEY的消息队列已经存在,client与server共享这个消息队列 for(i=10; i>=1; i--) { msg.mtype=i; msgsnd(msgqid,&msg,1024,0); //往msgqid发送消息msg printf("i=%d client:send\n",i); msgrcv(msgqid,&msg,1024,1000,0); //接收来自服务器进程的应答消息 } } } /*wait(0)表示将父进程挂起,有子进程结束时被唤醒*/ wait(0);//其中一个子进程结束被唤醒 wait(0);//另一个子进程结束被唤醒 return 0;}
4,编译并运行代码
[root@localhost os]# vim shiyan4_V3.c[root@localhost os]# gcc shiyan4_V3.c[root@localhost os]# ./a.out [root@localhost os]# i=10 server:receivedi=10 client:sendi=9 server:receivedi=9 client:sendi=8 server:receivedi=8 client:sendi=7 server:receivedi=7 client:sendi=6 server:receivedi=6 client:sendi=5 server:receivedi=5 client:sendi=4 server:receivedi=4 client:sendi=3 server:receivedi=3 client:sendi=2 server:receivedi=2 client:sendi=1 server:receivedi=1 client:send
结果显示,server和client端交替出现,由于client端一共发送了10次消息,所以i从10到1;
实验结果与预期效果有些不符,预期应该是:先显示 client:sent,再显示server:received,结果与之相反。如何解释?client和server是并发执行的2个进程,如果不加锁,两者可以随时抢占对方的CPU,这两个进程的调度顺序取决于顺序的调度程序,不是由我们写的代码决定的。初始时,由server建立一个消息队列,消息队列为空,由client向消息队列中发送第一个i=10的消息,此时消息队列里面有了一个消息,server抢断client的cpu,接收消息队列中的消息,于是server抢在client的前面先输出“i=10 server:received”。
5,注意事项
(1)修改应答消息的mtype,使其不与client发送的消息类型相同,此例中设置为1000。
(2)server端接收消息时,注意将msgrcv的第4个参数的合理范围【-999,-10】直接的整数。
msgrcv(msgqid,&msg,1024,-10,0);//server端接收消息
(3)client端接收server的应答消息时,msgrcv的第4个参数必须和应答消息的mtype相同,即1000。
msgrcv(msgqid,&msg,1024,1000,0); //接收来自服务器进程的应答消息
修改应答消息的mtype的作用是用来区别这两类消息:一是server端的应答消息,消息类型mtype=1000,二是client端发送给server端的消息,消息类型1<=mtype<=10。
server端接收消息时,假设msgrcv的第4个参数为0,即接收消息队列里的第1个消息,那么它就可能接收到刚刚它返回给client端的应答消息,而这是不合理的,我们希望应答消息只由client端来接收。设置msgrcv的第三个参数为-10,表示只能接收消息类型小于等于10的消息,由于应答消息的消息类型被设置为1000,于是server就不会错接收到应答消息。
在client端接收应答消息时,指定msgrcv的第4个参数为1000,保证了client端只接收应答消息,而不会接收自己发送给server的消息,避免出错。
(4)程序结束时,记得清空和删除消息队列。倘若不删除,消息队列会缓存在内存中,可能会影响下次程序的运行。
msgctl(msgqid,IPC_RMID,0);//清空并删除消息队列
6,仍待解决的问题
这个程序还有很多可以拓展的地方。
(1)如何让进程正常退出?
程序执行结束后,并没有自动回到shell进程,人为中断(例如ctrl+C)才能回到shell,如何让其自动回到shell?
...i=1 server:receivedi=1 client:send//此处没有自动回到shell进程[root@localhost os],需要人为中断
(2)如何实现client端先sent,server端再received?
上面分析过,这两个进程随时都会相互打断,如果一定要让client:send在前, server:received在后,该如何实现?
(3)使用2个消息队列?
(4)现实中,一个服务器往往是给成百上千或者成千上万的客户端服务的,如何模拟多个client发送的情况呢?
- 模拟进程通信
- 进程间通信——模拟键盘输入
- 父子进程的通信(非线程模拟 java)
- 安卓最简单的aidl用两个程序模拟进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 进程通信
- 习题1-3 连续和(1+2+3+······+n)
- 数据库基础题目(一)
- 二分查找
- 【10/28】 iOS开发成长之路,【tableView】
- 约瑟夫问题求解
- 模拟进程通信
- 扩展GCD算法学习笔记
- 解决Android中No resource found that matches android:TextAppearance.Material.Widget.Button.Inverse问题
- reverse()
- Robot Framework中使用HttpLibrary教程and中文支持
- 习题1-1 平均数 解题报告
- 京东首页很炫的js效果、图片自动滑动,悬停效果,鼠标离开效果
- linux常用命令
- Markdown 简明语法