操作系统管道通信.docx
- 文档编号:26093550
- 上传时间:2023-06-17
- 格式:DOCX
- 页数:30
- 大小:220.37KB
操作系统管道通信.docx
《操作系统管道通信.docx》由会员分享,可在线阅读,更多相关《操作系统管道通信.docx(30页珍藏版)》请在冰豆网上搜索。
操作系统管道通信
河南城建学院
《操作系统》课程设计说明书
设计题目:
管道通信
专业:
计算机科学与技术
指导教师:
邵国金郭猛薛冰
班级:
0814102
学号:
081410217
姓名:
金贺
同组人:
李乾坤邵光光
计算机科学与工程系
2011年1月10日
前言
课程设计是检测学生课程效果的重要手段,是训练学生通过所学的知识解决实际问题的重要方式,同时也是实践性教学中的一个重要环节,它以某以课程为基础,可以涉及和课程相关的各个方面,是一门独立于课程之外的特殊课程。
课程设计是让学生对所学的课程更全面的学习和应用,理解和掌握课程的相关知识。
《操作系统》是一门重要的专业课,是计算机理论和应用的核心基础课程。
操作系统课程设计,是一次对多学知识的综合演练,要求学生在操作系统的设计理念、整体机构、模块划分、数据结构的选择和应用、算法的设计及其实现等方面,加深对课程基本内容的理解,同时,在课程设计方法以及上机操作等基本技能和科学作风方面收到比较系统和严格的训练。
在这次的课程设计中我们选择的题目是进程间通信消息机制的设计,实现消息的创建、发送和接收及在server端创建一个服务函数,从而形成C/S通讯模式。
消息机制是消息通过消息队列的方式进行进程间消息的传递,通过此次课程设计,全面理解消息机制进程间通信方法。
实现把死板的课本知识变得生动有趣,激发了学生的积极性。
把学过的计算机操作系统的知识强化,能够把课堂上的知识通过自己设计的程序表示出来,加深了岁理论知识的理解目的。
目录
一、……………................................................................4
二、……………................................................................4
三、设计题目及要求........................................................................4
(1)设计管道通信…………………………………………………………4
(2)设计命名管道………………………………………..………………..4
四、总体设计……………................................................................4
五、详细设计……………................................................................6
1、实现管道通信…………………………………………………………..6
2、命名管道设计…………………………………………………………..8
六、调试与测试方法……………...................................................12
七、执行结果及分析……………...................................................13
八、源程序清单……………...........................................................14
九、心得体会……………...............................................................19
十、参考文献……………...............................................................19
三、系统环境
1、硬件环境:
Intel(R)Core(TM)2DuoCPU
E7200@2.53GHz
1.59GHz,2.00GB的内存
2、软件环境
MicrosoftWindowsXP
Professtonal
版本2002
ServicePack3
四、设计目的
利用UNIX系统提供的管道机制实现进程间的通信。
(1)管道通信。
利用pipe()和lockf()系统调用,编写程序,实现同族进程间的通信。
使用系统调用pipe()建立一条管道线;创建子进程P1,P2,…。
子进程Pi分别向管道各写信息,而父进程则从管道中读出来自于各子进程的信息,实现进程家族间无名管道通讯。
扩展之,使之成为客户/服务器模式,并完成一定的任务(自己定义)。
(2)命名管道通信:
利用mkfifo(name,mode)或mknod(name,mode,0)创建一个命名管道,然后利用它和文件部分系统调用实现不同进程间的通信。
改造之,使之成为客户/服务器模式,并完成一定的任务(自己定义)。
五、总体设计
1.fork()
创建一个新进程。
用法:
intfork()
其中返回int取值意义如下:
0:
创建子进程,从子进程返回的id值
>0:
从父进程返回的子进程id值
-1:
创建失败
2.lockf(files,function,size)
用作锁定文件的某些段或者整个文件。
头文件:
#include
参数定义:
intlockf(files,function,size);
intfiles,function;
longsize;
其中:
files是文件描述符;function是锁定和解锁;1表示锁定;0表示解锁;Size是锁定或解锁的字节数,若用0,表示从文件的当前位置到文件尾。
3.read
功能:
从描述符为filedes的文件读信息。
用法:
#include
ssize_tread(intfiledes,void*buff,size_tnbytes);
返回:
读到的字节数,若已到文件尾为0,若出错为-1。
在UNIX/Linux可重定义为:
intread(intfd,char*buff,unsignednbytes);
4.write
功能:
向已打开的文件写数据。
用法:
#include
ssize_twrite(intfiledes,constvoid*buff,size_tnbytes);
返回值:
若成功为已写入的字节数;出错为-1。
intwrite(intfd,char*buff,unsignednbytes);
文件位置指针
文件位置指针:
每个打开文件都有一个与其相关联的“当前位移量”。
是从文件开始处计算的字节数。
通常,读、写操作都从当前文件位置处开始,并使位移量增加所读或写的字节数。
按系统默认,当打开一个文件时,除非指定O_APPEND选择项,否则该位移量被设置为0,即指向文件的开始处。
文件位置指针可以通过系统调用lseek来移动。
5.创建
用mkfifo或mknod创建一个命名管道。
以mkfifo为例:
#include
#include
intmkfifo(constchar*fifo_name,mode_tmode);//成功返回0,否则为-1
6signal(sig,function)
允许调用进程控制软中断信号的处理。
头文件:
#include
参数定义
signal(sig,function)
intsig;
void(*function)();
返回值:
成功时返回旧的(以前)函数描述,失败时返回SIG_ERR。
7、client、server
可以以client/server方式使用FIFO。
如果一个服务器有多个客户时,每个客户可通过一个well_knownFIFO服务器连接。
连接后可以通过well_knownFIFO向服务器发送请求,所发信息的长度必须≤PIPE_BUF(4096)。
流程图
消息的创建、发送和接收示意图
六详细设计
1、实现管道通信
编制一段程序,实现进程的管道通信。
使用系统调用pipe()建立一条管道线。
两个子进程p1和p2分别向管道各写一句话:
child1issendingmessage!
child2issendingmessage!
而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。
<程序>
#include
main()
{
inti,r,p1,p2,fd[2];
charbuf[50],s[50];
pipe(fd);//创建匿名管道,fd[0]为读端,fd[1]为写端//
while((p1=fork())==-1);//创建子进程P1,直至成功为止(p1!
=-1)//
if(p1==0)//子进程P1执行逻辑//
{
lockf(fd[1],1,0);//锁定管道写端,保证写入数据的完整性//
sprintf(buf,"childprocessP1issendingmessages!
\n");//在buf中填入准备写入管道的信息数据
printf("childprocessP1!
\n");//打印“子进程P1正在运行”//
write(fd[1],buf,50);//向管道写端fd[1]写入buf中的数据,写完后该数据即可以从读端fd[0]读出//
sleep(5);//睡眠5秒//
lockf(fd[1],0,0);//解锁管道写端//
exit(0);//子进程P1退出//
}
else//主进程的执行逻辑//
{
while((p2=fork())==-1);//创建第二个子进程P2//
if(p2==0)//子进程P2的执行逻辑//
{
lockf(fd[1],1,0);//锁定管道写端,保证数据写入完整//
sprintf(buf,"childprocessP2issendingmessages!
\n");//在buf中填入准备写入管道的信息数据
printf("childprocessP2!
\n");//打印“子进程P2正在运行”//
write(fd[1],buf,50);//向管道写端fd[1]写入buf中的数据,写完后该数据即可从读端fd[0]读出//
sleep(5);//睡眠5秒//
lockf(fd[1],0,0);//解锁管道写端//
exit(0);//子进程P2退出//
}
//以下为主进程执行逻辑//
wait(0);//等待某个子进程退出//
if(r=read(fd[0],s,50)==-1)//从管道读端fd[0]读取P1或者P2写入的数据(视哪个子进程抢先执行到lockf函数)//
{
printf(:
can'treadpipe\n");//读取失败,打印错误信息//
}
else
{
printf(:
%s\n",s);//打印出读到的信息数据//
}
wait(0);//等待第二个子进程退出//
if(r=read(fd[0],s,50)==-1)//从管道读端fd[0]读取出P1或者P2写入的数据(视哪个子进程后执行到lockf函数)//
{
printf(:
can'treadpipe\n");//读取失败,打印错误信息//
}
else
{
printf(:
%s\n",s);//打印读取到的信息数据//
}
exit(0);//主进程退出//
}
}
2、命名管道设计。
命名管道的通信例子中包括client端和server端。
它们源代码文件名称分别为fifo_clt.c和fifo_svr.c,还有一个公共常量的有关文件被打包在文件fifo_hd.h
运行时,client只运行一次就将退出,而server端作为服务器仍将继续运行,你再次启动client来请求服务。
FIFO的用法
1、创建
用mkfifo或mknod创建一个命名管道。
以mkfifo为例:
#include
#include
intmkfifo(constchar*fifo_name,mode_tmode);//成功返回0,否则为-1
2、使用
管道一经创建,就可向普通文件一样使用。
可通过系统调用open,close,read,write,unlink等进行操作。
管道打开过程中,变量O_NONBLOCK将影响打开后对文件的操作。
默认情况下该变量不设置,也就是以阻塞方式打开。
这样可以保证原子性操作。
(因此可以不考虑该参数。
)
在操作过程中,如果对一个管道进行写操作write,若对方没有以读方式打开将产生SIGPIPE。
你可以捕获此信号进行处理。
默认情况下是出现写错误。
当最后一个写入者关闭了管道,将产生一个文件结束标志EOF。
3、client、server
可以以client/server方式使用FIFO。
如果一个服务器有多个客户时,每个客户可通过一个well_knownFIFO服务器连接。
连接后可以通过well_knownFIFO向服务器发送请求,所发信息的长度必须≤PIPE_BUF(4096)。
如果客户服务器模式是并发型的话,则客户机不能再通过well_knownFIFO回读信息。
此时可采用在已连接的客户与服务器之间建立一个私有通讯管道的办法来进行通信。
该私有管道被服务器创建后可以以I/O方式打开,用于客户机和服务器之间进行通讯,以完成指定性工作。
头文件
#definemy_fifo"my_fifo"/*定义头文件名*/
#definefile_name"server."/*定义头文件名*/
客户端程序
#include
#include
#include
#include"fifo_hd.h"
main(intargc,char**argv)
{
intfd1,fd2,pid,pid1;/*定义管道*/
charmy_buf[100];
charmy_fil[100];
charmy1buf[100];
if((fd1=open(my_fifo,1))==-1)
{
fprintf(stderr,"Openwell_knownFIFOforreadindError!
\n");
exit(-1);/*失败*/
}
fprintf(stderr,"Open%sOK!
\n",my_fifo);
pid=getpid();
sprintf(my_buf,"%5.5d%6.6d%7.7d",pid,pid*10,pid*20);
if(write(fd1,my_buf,20)!
=0){
strcpy(my_fil,file_name);/*拷贝*/
strncat(my_fil,my_buf,5);
fprintf(stderr,"Send_fil:
%s\n",my_fil);
sleep
(2);
if((fd2=open(my_fil,2))==-1){
fprintf(stderr,"open%sError!
\n",my_fil);
close(fd1);
exit(-2);
}
fprintf(stderr,"open%sOK!
\n",my_fil);
if(read(fd2,my1buf,5)!
=0){
my1buf[5]='\0';
fprintf(stderr,"Readfrommy_buf:
%s!
\n\tmy1buf:
%s",my_buf,my1buf);
if(strncmp(my_buf,my1buf,5)!
=0){
fprintf(stderr,"Differentoccurs!
\n");
}
strcpy(my_buf,"0000000000");
write(fd2,my_buf,5);
//sleep(5);
close(fd2);
close(fd1);
}
}
}
服务器程序
#include
#include
#include
#include
#include"fifo_hd.h"
voidterminate();
intwell_known_id,tmp_id;
chartmp_fil[100];
main(intargc,char**argv)
{
intfd1,fd2;
pid_tpid;
charmy_buf[100],my_fil[100],my_tmp[100];
sprintf(my_buf,"rm-f%s>/dev/null",my_fifo);
system(my_buf);//doshellcmdrm-fmy_fifo>/dev/null
well_known_id=tmp_id=-1;
signal(SIGINT,terminate);
if(mkfifo(my_fifo,S_IRWXU|S_IRWXG|S_IRWXO)==-1){
fprintf(stderr,"CreateWell_knownFIOFError!
\n");
exit(-1);/*创建失败*/
}
fprintf(stderr,"mkfifoOK!
\n");
fprintf(stderr,"ANewSeession!
I'mwaitingconnection...\n");
loop1:
/*输出字符串*/
if((fd1=open(my_fifo,0))==-1){
fprintf(stderr,"Openwell_knownFIFOforreadindError!
\n");
unlink(my_fifo);/*断链接*/
exit(-2);
}
well_known_id=fd1;
tmp_id=-1;
fprintf(stderr,"openmy_fifoOK!
\n");
if(read(fd1,my_buf,20)!
=0){
fprintf(stderr,"My_buff=%s\n",my_buf);
strcpy(my_fil,file_name);
strncat(my_fil,my_buf,5);
strcpy(tmp_fil,my_fil);
}
if((pid=fork())!
=0){
close(fd1);
wait();
gotoloop1;
}
fprintf(stderr,"Tmp_FIFOis:
%s|\n",my_fil);
if(mkfifo(my_fil,S_IRWXU|S_IRWXG|S_IRWXO)==-1){
fprintf(stderr,"Createmy_fil:
%sFIFOError!
\n",my_fil);
exit(-1);/*错误*/
}
//system("lsserver*");
if((fd2=open(my_fil,2))==-1){
fprintf(stderr,"Open%sError!
:
%d\n",my_fil,fd2);
close(fd1);unlink(my_fifo);
exit(-3);
}
tmp_id=fd2;
if(write(fd2,my_buf,5)!
=5){
fprintf(stderr,"Write%sError!
\n",my_fil);
close(fd2);close(fd1);
unlink(my_fil);unlink(my_fifo);
exit(-4);/*退出*/
}
sleep
(1);
if(read(fd2,my_tmp,5)!
=5){
fprintf(stderr,"read%sError!
\n",my_fil);
close(fd2);close(fd1);
unlink(my_fil);unlink(my_fifo);
exit(-5);/*退出*/
}
else{
if(strncmp(my_tmp,"00000",5)!
=0){
close(fd2);close(fd1);
fprintf(stderr,"Filedtofinishtalkingwith%s!
\n",my_fil);
unlink(my_fil);
exit(-1);/*失败*/
//gotoloop1;
}
else{
close(fd2);close(fd1);
fprintf(stderr,"OKtotalkingwith%s!
\n",my_fil);
unlink(my_fil);
//unlink(my_fifo);
exit(0);/*成功实现管道通信*/
}
}
}
voidterminate()
{
if(well_known_id!
=-1){
close(well_known_id);unlink(my_fifo);
}
if(tmp_id!
=-1){
close(tmp_id);unlink(tmp_fil);
}
fprintf(stderr,"TheServerProgramstopedbySignal:
SIGINT!
\n");
exit(0);
}
七、调试与测试
任务一编译方法:
编译:
ccliulong.c
执行:
./a.out
结果:
任务二编译方法是:
编译:
cc–ofifo_svrfifo_srv.c
cc–ofifo_cltfifo_client.c
执行:
先启动server端程序,方法为:
./fifo_svr
服务端:
再换一个终端运行client端,方法是:
./fifo_clt
客户端:
运行时,client只运行一次就将退出,而server端作为服务器仍将继续运行,你再次启动client来请求服务。
<任务一运行结果>正常:
管道实现通信
<任务二运行结果>出现错误如下:
服务器运行起初正常,然后当与客户端建立通信时由于客户端程序出错,导致整个通信出现错误。
由客户端引起的服务器程序运行出现错误
当服务
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 管道 通信