FTP协议的应用.docx

上传人:b****2 文档编号:2570428 上传时间:2023-05-04 格式:DOCX 页数:37 大小:335.69KB
下载 相关 举报
FTP协议的应用.docx_第1页
第1页 / 共37页
FTP协议的应用.docx_第2页
第2页 / 共37页
FTP协议的应用.docx_第3页
第3页 / 共37页
FTP协议的应用.docx_第4页
第4页 / 共37页
FTP协议的应用.docx_第5页
第5页 / 共37页
FTP协议的应用.docx_第6页
第6页 / 共37页
FTP协议的应用.docx_第7页
第7页 / 共37页
FTP协议的应用.docx_第8页
第8页 / 共37页
FTP协议的应用.docx_第9页
第9页 / 共37页
FTP协议的应用.docx_第10页
第10页 / 共37页
FTP协议的应用.docx_第11页
第11页 / 共37页
FTP协议的应用.docx_第12页
第12页 / 共37页
FTP协议的应用.docx_第13页
第13页 / 共37页
FTP协议的应用.docx_第14页
第14页 / 共37页
FTP协议的应用.docx_第15页
第15页 / 共37页
FTP协议的应用.docx_第16页
第16页 / 共37页
FTP协议的应用.docx_第17页
第17页 / 共37页
FTP协议的应用.docx_第18页
第18页 / 共37页
FTP协议的应用.docx_第19页
第19页 / 共37页
FTP协议的应用.docx_第20页
第20页 / 共37页
亲,该文档总共37页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

FTP协议的应用.docx

《FTP协议的应用.docx》由会员分享,可在线阅读,更多相关《FTP协议的应用.docx(37页珍藏版)》请在冰点文库上搜索。

FTP协议的应用.docx

FTP协议的应用

第九组:

FTP协议的应用

李伟深(电信113)学号1107400080

邓景杭(电信112)学号1107400058

孟永健(电信112)学号1107400043

孔志荣(电信112)学号1107400052

苏健(电信113)学号1107400054

叶云青(电信113)学号1107400057

叶杨杰(电信113学号1107400065

张铭魁(电信113)学号1107400067

甘启钊(电信113)学号1107400062

钟泽豪(电信113)学号1107400060

 

FTP服务器端设计说明书

1、概述

FTP作为文件传输协议(FileTransferProtocol),其任务务是从一台计算机将文件传送到另一台计算机,它与这两台计算机所处的位置、联系的方式、以及使用的操作系统无关。

FTP采用“客户机/服务器”方式,客户端要在自己的本地计算机上安装FTP客户程序,而服务器端则提供远程的访问和文件传输。

针对FTP的服务器端来说,主要为用户和管理员提供访问权限,并通过侦听端口以随时响应合法的客户请求。

通过控制通道和数据通道分别控制和响应对应的相关请求以及进行所需的数据文件传输。

响应的基本指令同标准的FTP协议规范以做到兼容现行的FTP客户端软件(如Flashxp等),同时主要要保证同本组对应的FTP客户端程序相兼容,确保其正确性和可扩展性。

基于服务器端的功能和特点,需要保证能够对端口进行实时侦听,及时响应客户端发送的命令,并由此打开控制通道,等待客户端用户的命令再做对应处理,开放数据通道进行信息和文件等数据的传输。

服务器需要能够对用户进行认证并对命令做出及时准确的回应,满足传输等需求。

由此在设计实现服务器端时,要能够建立一定的客户访问机制,设置权限,针对不同的用户确定相应的处理机制以实现“合法”的访问传输,更重要的一点是正确地解析来自客户端发出的请求命令,给予实时同时需准确无误地响应。

要在客户端完成登陆,退出,列目录,下载/上传文件,下载/上传目录,删除文件/目录,新建目录,断点续传等操作的基础上针对每个操作的对应命令做出回复完成合法用户所需的功能。

2、开发目标

设计并实现一个符合标准FTP协议规范的,并支持拥有登陆,退出,列目录,下载/上传文件,下载/上传目录,删除文件/目录,新建目录,断点续传以及传输过程中状态计算等功能的对应FTP客户端系统和兼容有同样功能的现行FTP客户端软件。

二、参考文档

《协议说明书》

《VisualC++6.0网络及Internet开发指南》

《VisualC++网络程序设计实例详解》

《VisualC++网络高级编程》

三、开发工具和平台

基于VisualC++6.0的SOCKET网络编程,在WindowsXPSP3下开发完成。

由于近阶段一直在使用VC6.0完成相关实习,并需要同客户端兼容,就决定采用VC6.0下的MFC支持SOCKET进行FTP的开发。

四、测试工具

由于并行开发和需要兼容现行FTP的缘故,为方便测试,采用Flashxp作为客户端软件调试,当然后期主要是直接同本组客户端进行连接测试。

5、程序结构

1)类定义

class

specification

CAlienFTPServerDlg

主对话框类,用于图形界面的处理,通过调用AlienFTPServerCmd类提供的函数实现支持客户端的请求并做出响应。

 

AlienFTPServerCmd

FTP命令处理类,该类主要负责实现功能需求的各种函数,供CAlienFTPServerDlg直接调用,同时也提供一些基本操作使CAlienFTPServerDlg可以通过这些操作的组合完成复杂的功能。

几乎所有的响应指令都是通过该类完成。

CAlienFTPServer

对应的工程类,基本没有完成相关操作

Adduser

用于增加用户的对话框类,实际中应由管理员进行分配,使用户在持有用户名和密码的情况下访问FTP服务器,同时也支持匿名登陆。

2)主要类接口

2.1CAlienFTPServerDlg类

classmember

function

OnStart

用于侦听客户端的请求以开启服务器的相关服务,它调用ThreadStart的线程处理该操作。

OnViewpath

用于浏览选择对应主机上的文件夹路径供用户访问,它同服务器端和客户端其它处理相同类型的操作所采用的方式基本相同。

OnAddUser

该功能比较简单,主要是跳出增加用户的对话框以设置相关信息,主要功能实现还是在AlienFTPServerCmd中。

2.2AlienFTPServerCmd类

该类完成的操作较为复杂,几乎所有服务器的处理工作都由它完成,故只针对部分进行介绍。

classmember

function

AddUser

增加访问服务器的用户操作,并将信息记录在Usernode的结构体中。

GetUserListHead

得到用户列表中的第一个用户信息(主要是用户名),其它如GetUserListLast等函数功能与之类似。

GetUserLogin

得到当前登陆的用户信息(用户名),其它如GetUserPasswd其功能和结构与之相似

GetUserStartDir

得到对应的用户登陆的根目录信息

StartListening

开启端口进行侦听,相应的StopListening则为结束侦听

IsListening

确定当前服务器是否处于Listening状态

StartAccepting

允许客户端接入服务器进行相应操作

SendReply

服务器对客户端相应命令作出的响应

CloseSocket

关闭套接字

BuildPath

根据客户的起始路径和控制构造相应路径

LIST_Command

处理客户端List等命令的功能

STOR_Command

处理客户端Stor等命令的功能

OpenDataConnection

因数据传输打开数据通道

3)线程定义

Thread

specification

ThreadStart

用于开启服务器响应服务时为其开辟的线程以防止服务器在忙于侦听和处理客户端请求时,无法响应其他的界面处理等操作。

5、功能模块设计

1)总体流程

服务器会先与客户端进行连接,一旦验证和连接成功完成后,服务器和客户端就会打开相关通道进行数据传送等操作。

2)新建用户

通过增加用户以允许合法的客户能够通过客户端成功连接服务器以获取所需信息和数据。

主要为用户创建以下信息:

用户名、登录密码及登录的初始根目录。

通过将信息加入UserNode的结构中记录可以访问的用户。

通过在Adduser类中调用AlienFTPServerCmd中的AddUser函数来实现,把相应账户、密码和路径通过参数传递,用AlienFTPServerCmd的对象ftpserver来通过AddUser完成,将User信息存入UserNode中。

如下:

AlienFTPServerCmd:

:

UserNode*FtpUser=(*ftpserver).AddUser(m_username,m_password,m_userpath);

3)侦听、启动连接

(以上结构同客户端)

新建用户后,通过开启服务,服务器端会对21端口进行不断侦听,当有相应客户端请求时,就会打开命令通道,当有数据传送时,再通过数据通道进行数据连接以传输文件等。

该功能如以上所说,通过在主对话框类ALienFTPServerDlg调用OnStart,并使用线程ThreadStart来实现侦听和连接。

以下为OnStart()函数:

voidCALienFTPServerDlg:

:

OnStart()//开启服务器

{

//TODO:

Addyourcontrolnotificationhandlercodehere

UpdateData(true);//更新在主对话框上得到的数据

pThreadStart=(HANDLE)_beginthreadex(NULL,

0,

ThreadStart,

(void*)this,

0,

&m_dwID);}

4)命令控制和响应模块

FTP协议模型

如第五部分介绍,整个服务器部分的主要命令控制和相应控制都在AlienFTPServerCmd类中实现,因此它是整个FTP的关键部分,而主要的处理命令都在一个while

(1)的“死”循环中执行,通过对每个列出的命令如"USER","PASS","MODE",TYPE","CWD","PWD"等进行对应的处理,并利用pszCmd和SendReply传送客户端的请求指令和服务器端的响应,为了清晰准确地反映执行过程的指令传送和响应结果,利用一个字符串str记录pszCmd和SendReply信息并在服务器主对话框上显示,以下是处理命令控制的while循环部分操作:

//主循环,不停地接受客户端发出的命令进行响应

while

(1){

CFtpServerEx->str1=pszCmd;//用str1记录pszCmd的信息,即客户端的请求命令

if(!

strcmp(pszCmd,"QUIT")){

CFtpServerEx->SendReply(Client,"221Goodbye.\r\n");//SendREply进行相应的处理表示

break;

}elseif(!

strcmp(pszCmd,"USER")){

if(Client->bIsLogged==true){

Client->bIsLogged=false;

Client->User->SClient+=-1;

Client->User=NULL;

}

if(!

pszCmdArg){

CFtpServerEx->SendReply(Client,"501Invalidnumberofarguments.\r\n");

}else{

if(CFtpServerEx->bAllowAnonymous&&!

strcasecmp(pszCmdArg,"anonymous")//处理匿名登录的情况

&&CFtpServerEx->AnonymousUser)

{

Client->bIsLogged=true;

Client->bIsAnonymous=true;

CFtpServerEx->SendReply(Client,"230UserLoggedIn.\r\n");

Client->User=CFtpServerEx->AnonymousUser;

}else{

Client->User=CFtpServerEx->SearchUserFromName(pszCmdArg);

if(Client->User&&Client->User->bIsEnabled==false)

Client->User=NULL;

CFtpServerEx->SendReply(Client,"331Passwordrequiredforthisuser.\r\n");

}}

continue;

}elseif(!

strcmp(pszCmd,"PASS")){//处理PASS指令

if(Client->bIsAnonymous){

Client->bIsLogged=true;

CFtpServerEx->SendReply(Client,"230UserLoggedIn.\r\n");

}else

6、小结

开始处理SOCKET网络编程时,确实无从着手,而且对MFC这一块很陌生,所以只好完成一些简单的基于对话框的操作,通过一定的适应逐渐了解相关方面的知识,应用也稍加点熟练。

毕竟是对SOCKET等方面的知识了解不够,最初只能通过相关实例来了解具体问题的应用和相关网络编程方面的知识。

总体来说,通过FTP的实现更加深了对网络协议尤其是FTP传输协议的了解,从而从深层次掌握相关方面的知识和应用。

 

FTP客户端设计说明书

1、概述

客户端感觉上要比服务器端简单一些,其实不然。

就我的开发体会而言,服务器端只要侦听21号端口,若有请求就打开控制通道,然后等待用户的命令做出相应的响应,并打开数据通道进行数据传输(目录列表或者文件),除了某些命令(例如USER和PASS),大部分的命令都是独立的,这就使得服务器端并不会存在复杂的有限状态机,特别是当我们并不需要实现其所有命令的时候(实际上我们实现了15条命令,具体见《协议说明书》)。

而客户端则是根据功能需求向服务器端发出各种指令来完成的,但是一些稍复杂的功能,例如目录的下载(或上传),服务器端并不提供这条命令,但是我们可以通过发出一系列其服务器提供的命令的组合来达到这个效果,生成这个命令组合便是客户端需要做的事之一。

这就有点像服务器提供少量“机器指令”,客户端则用这些少量的“机器指令”去“搭积木”来完成功能需求。

除此之外,客户端还要提供更多的图形元素,例如本地和远程的文件目录列表等。

在我们这个客户端的设计中,我们共完成了登陆,退出,列目录,下载/上传文件,下载/上传目录,删除文件/目录,新建目录,断点续传以及传输过程中状态计算(比如下载速度,下载时间和剩余时间、传输进度百分比的计算等等)等功能,并通过多线程的方法使得整个软件不至于在下载或上传时出现由于某个函数的繁忙计算而导致界面“死掉”的情况。

由于我们是并行开发的,即我完成客户端,同时另一些同学完成服务器端,所以我在开发时就没法用他们写的服务器端来进行测试。

取而代之的是,我用了主流的FTP服务器端软件Serv-U来测试我写的客户端。

2、开发目标

设计并实现一个符合标准FTP协议规范的,拥有登陆,退出,列目录,下载/上传文件,下载/上传目录,删除文件/目录,新建目录,断点续传以及传输过程中状态计算等功能的FTP客户端软件。

二、参考文档

《协议说明书》

《VisualC++6.0网络及Internet开发指南》

《VisualC++网络程序设计实例详解》

《VisualC++网络高级编程》

三、开发工具和平台

VisualC++6.0,在WindowsXPSP3下开发。

之所以选择VisualC++,是因为我本身对于VC的图形界面编程较为熟悉,相对而言对于java的图形界面的编程不是很熟悉(虽然java是以网络应用见长的)。

而不同的语言提供的socket接口又大体上差不多,所以我选择了VC来作为开发工具。

四、测试工具

Serv-U6.3。

正如上文所说,我们是并行开发的,所以我的客户端只能通过连接现有的FTP服务端软件来测试,这里我选择了使用较广,操作方便的Serv-U。

3、程序结构

1)类定义

class

specification

CAlienFTPClientDlg

主对话框类,用于图形界面的处理,通过调用AlienFTPCmd类提供的函数实现与服务器的连接与交互。

AlienFTPCmd

FTP命令处理类,该类主要负责实现功能需求的各种函数,供CAlienFTPClientDlg直接调用,同时也提供一些基本操作使CAlienFTPClientDlg可以通过这些操作的组合完成复杂的功能。

GetDirName

用于弹出对话框让用户输入待新建的目录的名称

RmdDialog

用于询问用户是否要删除一个远程的非空目录。

RestDialog

本来打算用此对话框来在待传输的文件在接收方已存在时询问用户选择续传还是覆盖的对话框类,但是由于在线程中弹出对话框总是出错,所以后来就用在主对话框中加一单选框代替,寒假有时间我会尽量修正这个问题。

2)主要类接口

2.1CAlienFTPClientDlg类

classmember

function

FindLocFile

根据指定的本地路径将该路径下的文件以列表的形式在主对话框的ListControl中显示出来

OnInsertFile

被FindLocFile调用,用于向表示当前的本地目录的ListControl插入一条目录/文件信息

InsertServerFile

用于向表示当前的远程目录的ListControl插入一条目录/文件信息

GetFileIcon

用于查找本地文件/目录的图标

GetFileIcon2

用于根据远程文件/目录的的文件类型在本机查找对应类型注册的图标

RemoveLocalDirectory

删除本地目录

OnDblclkListLocal

本地文件列表的双击响应事件函数,用户进入某个本地目录,并显示该目录里的文件列表

OnButtonBacklocal

本地文件列表的返回上一目录的响应函数

OnButtonConnect

与服务器连接的函数

OnButtonLogoff

与服务器断开的函数

OnDblclkListServer

远程文件列表的双击响应事件函数,用户进入某个远程目录,并显示该目录里的文件列表

OnButtonBackserver

远程文件列表的返回上一目录的响应函数

OnDownload

下载,在该函数中,将启动一个线程用于下载任务

OnUpload

上传,在该函数中,将启动一个线程用于上传任务

OnLocalDel

删除本地某个文件

OnServerDel

删除远程某个文件

OnLocNewDir

在本地的当前路径下新建目录

OnSerNewDir

在远程的当前路径下新建目录

OnRefreshLoc

刷新本地文件列表

OnRefreshSer

刷新远程文件列表

2.2AlienFTPCmd类

classmember

function

Open

打开命令通道

Close

关闭命令通道

Order

向服务器端发送一条命令

Response

接受服务器端的响应

Command

向服务器端发送一条命令并接受回应

GetFileItem

从服务器端发回的包含列表信息的数据中读取一条文件/目录信息

List

向服务器端发送LIST命令并接受服务器端在数据通道传输过来的文件列表数据

MoveFile

用于单个文件的上传/下载

LogOn

登陆服务器

LogOff

断开服务器

线程定义

Thread

specification

ThreadTime

定时器线程,用于下载/上传的已用时间,剩余时间的计算和显示

ThreadStatus

状态量计算线程,用于显示当前传输文件名,已传输大小,平均下载速度,下载进度的计算和显示

ThreadDownload

下载线程,根据下载的是文件或目录进行相应的下载任务,在下载目录的时候,该线程还负责传输队列的显示和更新

ThreadUpload

上传线程,根据上传的是文件或目录进行相应的上传任务,在上传目录的时候,该线程还负责传输队列的显示和更新

5、功能模块详细设计

5)登陆

登陆相对而言其他功能要简单得多,流程如下:

打开命令通道相应代码:

m_Ctrlsok=socket(AF_INET,SOCK_STREAM,0);

//建立套接字失败,则返回false

if(m_Ctrlsok==SOCKET_ERROR)

{

nRet=closesocket(m_Ctrlsok);

:

:

WSACleanup();

returnFALSE;

}

//定义结构体sockaddr_in,用于设置地址信息。

structsockaddr_insockAddr;

//将一个点间隔地址转换成一个in_addr

sockAddr.sin_addr.S_un.S_addr=inet_addr(serverhost.GetBuffer(serverhost.GetLength()));

//设置协议族,在socket编程中只能是AF_INET

sockAddr.sin_family=AF_INET;

//将主机的无符号短整形数转换成网络字节顺序

sockAddr.sin_port=htons(serverport);

//连接服务器

if(0!

=(connect(m_Ctrlsok,(sockaddr*)&sockAddr,sizeof(sockAddr)))){

returnFALSE;

}

这样,控制通道就打开了,向服务器端发命令时使用如下语句(命令在outputstring中):

send(m_Ctrlsok,outputstring.GetBuffer(outputstring.GetLength()),outputstring.GetLength(),0);

接受服务器端回应使用如下语句:

recv(m_Ctrlsok,readbuf,1024,0);

通过服务器端回应的前三位的回应码(详见《协议说明书》)来判断命令执行情况,即成功或失败。

2)退出

向服务器端发送“QUIT”命令即可。

3)列目录

列文件目录稍复杂点,但实际上也很简单,其复杂部分在于将服务器发过来的文件信息数据进行解析并得到相应的文件名,文件类型,文件大小,创建时间和权限等,处理流程如下:

其中发送命令于接受回应已在上文解释过,下面我们探讨关于PORT命令、LIST命令和侦听的socket。

在发送PORT命令之前要确保本地已经创建好了侦听socket,然后将该socket的地址和端口号转换为xxx,xxx,xxx,xxx,xxx,xxx(其中前四个xxx是将ip地址中的点换成逗号,后两个xxx实际上分别是port/256和port%256)作为PORT命令的参数发送给服务器端,服务器收到该条命令后会创建一个socket来连接我们已经在侦听的socket,这样,数据通道就建立好了。

接着发送一条LIST命令,客户端便将当前远程目录下的文件信息从数据通道发送过来,我们对接受到的数据进行解析便可以得到每个文件/目录具体的信息,如文件名,文件类型,文件大小,创建时间和权限等。

侦听socket的创建如上文所述,其用于侦听要涉及到有关socket的另外三个函数,分别是getsockname、bind和listen。

intPASCALFARgetsockname(SOCKETs,structsockaddrFAR*name,intFAR*namelen);

getsockname()函数用于获取一个套接口的名字。

它用于一个已捆绑或已连接套接口s,本地地址将被返回。

本调用特别适用于如下情况:

未调用bind()就调用了connect(),这时唯有getsockname()调用可以获知系统内定的本地地址。

在返回时,namelen参数包含了名字的实际字节数。

intPASCALFARbind(SOCKET

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2