操作系统课程设计说明书.docx
《操作系统课程设计说明书.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计说明书.docx(14页珍藏版)》请在冰豆网上搜索。
操作系统课程设计说明书
中北大学
操作系统课程设计
说明书
学院、系:
软件学院
专业:
软件工程
学生姓名:
崔健
学号:
0921010524
设计题目:
基于Linux的小型远程FTP服务系
统的设计
起迄日期:
2011年12月22日-2012年1月7日
指导教师:
薛海丽
2012年1月7日
1.需求分析
1.1设计目的
ftp远程服务是操作系统的重要功能之一。
用高级语言编写和调试一个简单的FTP服务系统,掌握对进程、线程、进程互斥、同步、通信、文件系统及网络编程的方法。
从而加深对远程服务机制的理解和认识。
1.2设计内容和要求
客户端的要求
a)客户通过身份请求后创建一个新线程来响应客户请
b)客户可以完成目录的创建,删除,切换,查看当前目录下的文件。
c)客户可以上传和下载目录到指定的文件夹。
服务端的要求
a)验证用户的登录信息。
b)支持多线程的使用。
c)记录活动客户数,客户在线数目加1,断开连接减1.
2.总体设计
客户端与服务端建立连接模块:
网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。
其具有一个类似于打开文件的函数调用socket(),返回一个整形的Socket描述符,随后的连接建立,数据传输等操作都是通过该Socket实现的。
常用的Socket类型有两种:
流式Socket和数据报式Socket。
流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。
本系统使用前者。
在使用socket进行网络传输之前,必须配置该socket。
Bind函数将socket与本机上的一个端口相关联,随后就可以在该端口发起向服务端的请求和监听服务请求。
面向连接的socket客户端通过调用Connect函数在socket数据结构中保存远端信息并与远端服务器建立一个TCP连接。
只有面向连接的客户程序使用socket是才需要将此socket与远端主机相连。
面向连接的服务器从不启动一个连接,它只是被动的在协议端口监听客户的请求。
Listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。
Accept()函数让服务器接受客户的连接请求,当accept()函数监视的socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这个新socket和请求连接进程的地址联系起来,收到服务请求的初始socket仍可以继续在以前的socket上监听。
系统中的fork()函数生成一个子进程来处理数据传输部分,fork()函数对于子进程返回的值为0,所以包含fork函数的if语句是子进程代码部分,它与if语句后面的父进程代码部分并发执行。
客户端发送操作命令和服务端接受命令执行相应的操作:
send()和recv()函数用于面向连接的socket上进行数据传输。
Send()函数返回实际上发送出去的字节数,可能会少于你希望发送的数据。
在程序中应将send()的返回值与欲发送的字节数进行比较。
当send()返回值与len不匹配时,应该对这种情况进行处理。
Recv()函数返回实际上接受的字节数。
接受到客户端的命令后,确定要执行的那个命令,进入相应的子模块,完成相应的操作。
总体流程
客户端流程
服务器端流程
3.详细设计
本系统的开发过程中,我做的是处理客户端发来的请求并调用系统函数执行相应的操作这一模块。
服务端接受并处理cd,ls,quit,mkdir,rmdir,upload,download这样几种类型的客户端发来的命令。
Cd工作路径:
修改当前工作路径;ls工作路径:
列出工作路径下的内容列表;quit:
客户端退出系统;mkdir目录名称:
在当前的工作路径下建立一个由参数确定的目录;rmdir目录名称:
在当前工作路径下删除给定名称的目录;upload:
将客户程序所在文件夹下的要求上传的文件上传到要求上传到的服务器端的那一文件夹下;download:
将操作的当前工作路径下的指定的某一文件下载到客户程序所在的文件夹中。
使用while循环不断接受客户发来的命令请求,并在客户端发来quit命令后,跳出循环,调用close()函数来释放该通讯的socket,从而停止在该socket上的任何数据操作。
while
(1){
bzero(buffer,BUFFER_SIZE);
printf("请输入指令:
");
getstr(cmd);
charaction[10]="";if(strcmp("cd",strncpy(action,cmd,2))==0||strcmp("ls",strncpy(action,cmd,2))==0||strcmp("quit",strncpy(action,cmd,4))==0||strcmp("rmdir",strncpy(action,cmd,5))==0||strcmp("mkdir",strncpy(action,cmd,5))==0){
write(client_socket,cmd,sizeof(cmd));
read(client_socket,buffer,BUFFER_SIZE);
printf("%s\n",buffer);
if(strcmp("quit",strncpy(action,cmd,4))==0){
//printf("Bye!
");
break;
}
}elseif(strcmp("download",cmd)==0){
bzero(file_name,FILE_NAME_MAX_SIZE+1);
printf("PleaseInputFileNameOnServer:
\t");
getstr(file_name);
strcpy(buffer,"download");
strcat(buffer,file_name);
//strncpy(buffer,file_name,strlen(file_name)>BUFFER_SIZE?
BUFFER_SIZE:
strlen(file_name));
//向服务器发送buffer中的数据
//send(client_socket,buffer,BUFFER_SIZE,0);
write(client_socket,buffer,sizeof(buffer));
bzero(buffer,BUFFER_SIZE);
//取得服务端发来的是否存在文件的信息
read(client_socket,buffer,BUFFER_SIZE);
if(strcmp(buffer,"文件不存在")==0){
printf("您请求的文件不存在!
\n");
continue;
}else{
FILE*fp=fopen(file_name,"w");
if(NULL==fp){
printf("File:
\t%sCanNotOpenToWrite\n",file_name);
continue;
}
//从服务器接收数据到buffer中
bzero(buffer,BUFFER_SIZE);
intlength=0;
length=recv(client_socket,buffer,BUFFER_SIZE,0);//循环接收,再写到文件,现在的水平只能实现文件的大小小于sizeof(buffer)
//{
if(length<0){
printf("RecieveDataFromServerFailed!
\n");
continue;
}
//intwrite_length=write(fp,buffer,length);
intwrite_length=fwrite(buffer,sizeof(char),length,fp);
if(write_lengthprintf("File:
\t%sWriteFailed\n",file_name);
continue;
}
//bzero(buffer,BUFFER_SIZE);
//}
printf("RecieveFile:
\t%sFromServerFinished\n",file_name);
fclose(fp);
}
bzero(file_name,FILE_NAME_MAX_SIZE+1);
read(client_socket,buffer,BUFFER_SIZE);
printf("%s\n",buffer);
*///break;
}elseif(strcmp("upload",cmd)==0){
bzero(file_name,FILE_NAME_MAX_SIZE+1);
printf("PleaseInputFileNameOncurrentcategory:
\t");
getstr(file_name);
FILE*fp=fopen(file_name,"r");
if(NULL==fp){
printf("File:
\t%sNotFound\n",file_name);
continue;
}else{
strcpy(buffer,"upload");
strcat(buffer,file_name);
write(client_socket,buffer,sizeof(buffer));
bzero(buffer,BUFFER_SIZE);
intfile_block_length=0;
while((file_block_length=fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0){
printf("file_block_length=%d\n",file_block_length);
//发送buffer中的字符串到new_server_socket,实际是给客户端
if(send(client_socket,buffer,file_block_length,0)<0){
printf("SendFile:
\t%sFailed\n",file_name);
break;
}
bzero(buffer,BUFFER_SIZE);
}
close(fp);
fclose(fp);
printf("File:
\t%sTransferFinished\n",file_name);
}
}else{
printf("无效指令,请重新输入\n");
}
}
//关闭socket
close(client_socket);
return0;
}
charfile_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name,FILE_NAME_MAX_SIZE+1);
printf("PleaseInputFileNameOnServer:
\t");
scanf("%s",file_name);
charbuffer[BUFFER_SIZE];
bzero(buffer,BUFFER_SIZE);strncpy(bufferfile_name,strlen(file_name)>BUFFER_SIZE?
BUFFER_SIZE:
strlen(file_name));
//向服务器发送buffer中的数据
send(client_socket,buffer,BUFFER_SIZE,0);
FILE*fp=fopen(file_name,"w");
if(NULL==fp)
{
printf("File:
\t%sCanNotOpenToWrite\n",file_name);
exit
(1);
}
bzero(buffer,BUFFER_SIZE);
intlength=0;
while(length=recv(client_socket,buffer,BUFFER_SIZE,0))
{
if(length<0)
{
printf("RecieveDataFromServer%sFailed!
\n",argv);
break;
}
intwrite_length=write(fp,buffer,length);
intwrite_length=fwrite(buffer,sizeof(char),length,fp);
if(write_length{
printf("File:
\t%sWriteFailed\n",file_name);
break;
}
bzero(buffer,BUFFER_SIZE);
}
printf("RecieveFile:
\t%sFromServer[%s]Finished\n",file_name,argv);
close(fp);
length=recv(client_socket,buffer,BUFFER_SIZE,0);//循环接收,再写到文件
if(length<0){
printf("RecieveDataFromServerFailed!
\n");
continue;
}
//intwrite_length=write(fp,buffer,length);
printf("%d\n",length);
intwrite_length=fwrite(buffer,sizeof(char),length,fp);
close(fp);
printf("%d\n",write_length);
printf("%s\n",buffer);
if(write_lengthprintf("File:
\t%sWriteFailed\n",file_name);
continue;
}
//bzero(buffer,BUFFER_SIZE);
4.心得体会
通过这次课程设计,我们不仅对C语言的知识重新巩固,而且通过查阅相关资料,对Linux的操作系统有了新的认识。
1.Linux不同于Windows,主要体现在操作界面,及一些软件的兼容性。
如在Windows
下是可执行文件,而在Linux成为普通的文件,甚至不能进行操作。
2.对Linux下的指令操作有了新的认识与理解,Linux操作系统有好多不同的版本,
但是所有的操作指令几乎都一样,更便于学习使用。
3.真正的多线程并发执行,多个用户可以同步进行操作,并且互不影响,这也是本次设计的任务之一。