ftp服务器详解+源代码.pdf
《ftp服务器详解+源代码.pdf》由会员分享,可在线阅读,更多相关《ftp服务器详解+源代码.pdf(38页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、一个简单的 FTP 服务器 实例目标 FTP 是网络上共享资源的常用方法,在本章中我们将实现一个简单的 FTP 服务器。本章知识点:FTP 协议 Socket 类和 TcpListener 类 名称空间 实例功能 本实例实现一个简单的 FTP 服务器,该服务器是一个控制台程序,编译后的可执行文件为,在控制台中键入 ftpd 后就可启动服务器,若要改变 ftp 服务器的工作目录,可以键入 ftpd r 后接绝对路径。服务器的 ftp 服务端口采用默认的 21。服务器启动后,用户就可从其他任何一台联网计算机进行访问。下面是应用的一个例子:(服务器所在机器的 ip 为)用户在自己计算机的控制台中输入
2、 ftp 回车后可以看到服务器传过来的欢迎信息,并要求输入登陆账号(图 5-1)。图 5-1 登陆 ftp 输入用户名和密码后(为简化起见我们在程序中省去了验证过程,任何人都可以登陆),用户的控制台如图 5-2 所示,在服务器上,也出现了该用户的登陆情况(图 5-3)。图 5-2 成功登陆 图 5-3 服务端 接下来用户可以使用各种命令进行各种 ftp 操作,比如列出目录下所有文件和文件夹(ls),下载指定的文件(get),上载文件(put)等等。下面是客户端(图 5-4)和服务端(图5-5)某时刻的运行状态。图 5-4 客户端运行情况图 5-5 服务端运行情况 编程思路 要实现 FTP 服务
3、器,我们必须对 FTP 协议有一定的了解,使用符合协议的指令集和网络传输方式,我们将在下一节详细介绍关于FTP协议的基础知识。另外,我们还采用了TcpListener和 Socket 编程技术实现数据传输,所以这也是我们需要掌握的内容。最后,为了同时给多个用户提供服务,FTP 服务器还必须支持多线程。FTP 服务器程序的大框架是这样的:程序运行后,在服务器的某个端口有一个 TcpListener一直在监听用户的请求,当有用户请求服务时,服务器立刻创建一个新的线程处理这个请求,我们称开始了一个新的会话。在会话中,服务器通过 Socket 接收用户命令,对命令进行分析后采取相应的操作,并将结果返回
4、。一直到用户退出这个会话,服务器才销毁这个线程。服务器和客户端的会话方式有两种,一是被动方式(passive),即服务器在某个特定端口有一个 TcpListener 在不断监听用户命令;二是主动方式,这种情况下,服务器在该客户端有服务请求时,创建一个套接字和它进行数据传输。关键技术 FTP 协议 1)概述 FTP 的目标是提高文件的共享性,提供非直接使用远程计算机,使存储介质对用户透明和可靠高效地传送数据。图 5-6 是 FTP 服务示意图,为了让大家更好的理解,我们先解释一下相关的概念。(1)字节大小,在 FTP 中字节大小有两个:逻辑字节大小和用于传输的字节大小。后者通常是 8 位,而前者
5、可不一定是多少了。传输字节不必等于逻辑字节大小,也不必对数据结构进行解释。(2)控制连接是建立在 USER-PIT 和 SERVER-PI 之间用于交换命令与应答的通信链路。(3)数据连接是传输数据的全双工连接。传输数据可以发生在服务器 DTP 和用户 DTP之间也可以发生在两个服务器 DTP 之间。(4)DTP:数据传输过程,DTP 建立和管理数据连接,可以是主动的也可以是被动的。(5)EOR 代表记录尾。(6)NTV 代表网络虚拟终端。(7)NVFS 代表网络虚拟文件系统。(8)FTP 可以传输非连续的文件,这些文件的一部分称为页。(9)PI 代表协议解释器。(10)服务器 DTP 代表一
6、种传输过程,它通常处于“主动”状态,它和侦听端口建立数据连接,它还可以为传输和存储设置参数,并根据 PI 的指令传输数据。当然,DTP 也可以转入“被动”状态。(11)服务器 FTP 进程,它是和用户 FTP 进程一起工作的,它由 PI 和 DTP 组成。至于用户 FTP 进程则是由 PI,DTP 和用户接口组成的。图 5-6 FTP 服务示意图 注意:数据连接是双向的,它不用整个时间都存在。上图中用户 PI 开始控制连接,控制连接与 Telnet 协议很象。在开始阶段,标准 FTP 命令由用户 PI 产生并通过控制连接传送到服务器进程。服务器 PI 向用户 PI 返回标准应答。FTP 命令指
7、定数据连接参数和文件系统操作。用户 DTP 在特定数据端口侦听,服务器开始数据连接并以指定的参数开始数据传输。数据端口不必在开始 FTP 命令的机器上,但用户或用户 FTP 进程必须确定它在指定的数据端口上侦听。这个数据连接是全双工的。在另外一种情况下,用户或许希望在两个主机间传送文件,不是两个本地主机。用户在两台主机间建立控制连接,然后规划数据连接。用这种方式,控制信息由用户 PI 获得,但是数据在服务器 DTP 之间传送。图 5-7 就是一个例子:图 5-7 协议要求数据传输在处理时打开控制连接。在完成 FTP 服务后由用户中止控制连接,而服务器具体操作。如果在未接收命令时关闭了控制连接,
8、服务器也会关闭数据传输。数据传输功能 数据连接只传输数据,控制连接传送命令和响应。几个命令是关于在主机间传输数据的,数据传输基本上独立于物理结构的,但是如果在压缩传输模式下流式传输与文件结构有关,文件的属性与表示类型有关。数据表示与保存 数据是在主机间的存储设置间传送的。因为两个系统的数据存储方式不同,因此需要对它进行转换,在传送文本时会有对 ASCII 表示的问题,在进行二进制传送的时候,会有不同系统对字节长度规定不同的问题,有的系统是 7 位,有的系统可能是 32 位,这也需要进行转换。需要提供数据表示与传输模型函数,但是 FTP 提供这方面的功能不多,超过 FTP 提供功能的那一部分要用
9、户自己实现。数据表示是由用户指定的表示类型,它可以是隐含的,也可以是用户指定的。请一定注意:逻辑字节长度与物理字节长度是不同的。ASCII 类型:这是所有 FTP 必须实现的默认类型,用于传送文本文件,当在主机间使用 EBCDIC 传送时更方便,则不使用 ASCII 类型。发送方将内部表示转换为 NVT-ASCII 格式,接收方则进行相反的过程接收数据。根据 NVT 标准,要在行结束处使用序列。NVT-ASCII 是 8 位的。ASCII和 EBCDIC 的格式参数在下面讨论。EBCDIC 类型:它是作为 ASCII 的另一种方法在主机间传送数据的数据类型。EBCDIC 和 ASCII 很象,
10、仅在类型的功能描述上有一些差别。行结束符使用很少。图象类型:在此类型下传送的数据被看作连续的位,发送方将数据打包到 8 位传输字节中传送。因为结构的需要要对传送数据进行填充,填充字节全部为 0,填充必须在文件结构时使用,而且要标记出以便接收方过滤掉。它用于传送二进制数据和有效地传送和存储文件,因此所有FTP 也必须实现。本地类型:也可以以十进制指定逻辑字节大小。如果物理字节大小和逻辑字节大小不同,直接将物理数据打包为逻辑字节,不用什么填充。接收方根据逻辑字节大小进行和本机的存储特点进行转换。传输必须是可重复的,也就是说,相同的文件相同的参数,那内容必须是一样的。数据结构 除了有不同的数据类型外
11、,FTP 还允许有不同的文件结构,下面是三种文件结构:文件式结构:文件中没有内部结构,文件被看作是二进制流;记录结构:文件是由一系列记录组成的;页结构:文件是由不同的索引页组成的。如果未使用 STRU 命令,文件结构是默认值。文件的结构会影响传输模型,存储和数据表示。文件本来的属性和保存它的主机有关,不同的机器会以自己的方式保存文件。在不同主机间传送文件时必须使主机能够识别相互的表示。有些主机上的文件是面向字节的,有些是面向记录的,在传送时就会出现问题。那就要在接收方进行内部转换。在进行转换的时候,需要区别记录的边界,在 ASCII 中使用,在 EBCDIC 中使用作为分隔符。采用这种实现方法
12、的必须保证转换是可逆的。文件结构:如果未使用 STRU 命令,文件结构是默认值。文件结构中没有默认值,文件被看作是连续的字节串。记录结构:对于文本文件,记录结构必须是所有 FTP 实现必须有的。记录结构文件是由连续的记录构成的。页结构:文件是非连续时使用页结构。这种文件称为随机访问文件。这些文件中有时会的和文件整体或部分相关的信息出现。在 FTP 中,文件的一个部分称为页。建立数据连接 传送数据机制包括建立连接选择数据参数。用户和服务器 DTP 有默认数据端口。用户进程默认数据端口和控制连接端口相同。服务器进程默认数据端口和控制连接端口相邻。传输字节大小是 8 位字节。此字节是实际传输字节,但
13、不代表主机内的数据表示。被动数据传输进程在数据端口接收数据,FTP 请求命令决定数据传输的方向。服务器在接收到请求以后,将初始化端口的数据连接。当连接建立后,传输在 DTP 之间传送,服务器 PI 对用户 PI 返回应答。FTP 实现运行一个默认数据端口,用户 PI 才能改变默认端口。通过 PORT 命令可能改变端口,用户可能希望数据在第三方主机上进行其它操作,用户PI 需要在两个服务器 PI 上建立连接。一个服务器被告知侦听另一服务器的请求。用户 PI 通过 PORT 命令通知另一服务器的数据端口。最后双方发送相应的传送命令。通常,服务器负责支持数据连接,初始化并关闭它,除非用户 DTP 在
14、传输模式下要求关闭连接。服务器在下面情况下关闭数据连接:服务器结束发送数据,通过 EOF 要求中止传送;用户发送 ABORT 命令;用户改变端口;控制连接关闭;发生不可恢复错误。数据连接管理 默认数据连接端口:所有 FTP 必须支持默认数据连接,只有用户 PI 能够初始化非默认端口的使用。确定非默认数据端口:用户 PI 可以使用 PORT 命令指定非默认端口,它要求服务器方以PASV 确定非默认数据端口。连接是由双方地址确定的,因此改变一方地址就改变了连接。数据连接的重用:在使用流式数据传输模型时,文件结束通过关闭连接指示。如果要传送多个文件时就会出麻烦,解决的方法有两个,一个是确定非默认端口
15、,另一个是使用另一种传输模式。就传输模式而言,流传输模式是不安全的,因此无法确定连接是暂时还是永久关闭。其它传输模式不通过关闭连接表示文件结构,它们可以通过 FTP 命令决定传送结构。因此使用这些传输模式可以在保持连接的情况下传送多个文件。传输模式 有三种传输模式:一种将数据格式化并考虑重新开始过程;一种压缩数据;一种是不经过处理(少量处理)传送。所有数据传输必须以一个 EOF 结束,它可以显式给出,也可以通过关闭连接隐式给出。对于记录文件,所有 EOR 是显式的,包括最后一个记录。对于以页结构传送的文件,使用“最后一页”表示结束。从这里开始,下文中我们提到的字节指的是“传输字节”。为了进行标
16、准化传送,传送主机必须把行结束或记录结束的内部表示转化为传输模式和文件结构指定的形式传送,接收方则进行相反的工作。IBM 大型机的记录计数域可能不能为其它主机识别,所以记录结束标记在流模式下以双字节控制码传送,在块或压缩模式下以标记位传送。而 ASCII 或 EBCDIC 的行结束则则或指示。这样的转换需要时间,所以相同的系统在传送文本文件时采用二进制或流表示比较合适。下面是 FTP 定义的传输模式:流模式:数据以字节流的形式传送。使用的表示类型没有限制,允许记录结构。在记录结构文件EOR 和 EOF 表示为双字节控制码。第一字节全为 0,后一字节为转义字符。当第二位值为 1时表示 EOR,为
17、 2 时表示 EOF,如果要同时表示 EOR 和 EOF,值为 3。全 1 字节作为数据发送时必须使用双字节传送,其中数据保存在第二个字节内。如果是文件结构,通过发送方关闭连接表示 EOF,接收到的所有数据就是文件内容。块模式:文件以块形式传送,块带有自己的头部分。头字节包括计数域和描述子代码。关于 FTP 协议的基本知识我们先介绍这些,在以后的代码分析中我们将结合实例,做更深入的讨论。基于 TCP 协议的网络通讯 TCP 协议是一个基本的网络协议,基本上所有的网络服务都是基于 TCP 协议的,FTP 也是,所以必须了解基于 TCP 协议的编程。然而 TCP 协议是一个庞杂的体系,要彻底的弄清
18、楚它的实现不是这么容易,不过在.NET Framework 环境下,我们不必要去追究 TCP 协议底层的实现,一样可以很方便的编写出基于 TCP 协议进行网络通讯的程序。在这章里,我们主要通过两个类编写 FTP 服务程序,这两个类是:TcpListener 类和 Socket类,它们都属于名称空间。Socket 类简介 Socket(套接字)是通信的基石,是支持 TCP/IP 协议的网络通信的基本操作单元。可以将 Socket 看作不同主机间的进程进行双向通信的端点,它构成了单个主机内及整个网络间的编程界面。Socket 存在于通信域中,通信域是为了处理一般的线程通过 Socket 通信而引进
19、的一种抽象概念。Socket 通常和同一个域中的 Socket 交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序)。各种进程使用这个相同的域互相之间用 Internet 协议簇来进行通信。Socket 可以根据通信性质分类,这种性质对于用户是可见的。应用程序一般仅在同一类的 Socket 间进行通信。不过只要底层的通信协议允许,不同类型的 Socket 间也照样可以通信。Socket 有两种不同的类型:流 Socket 和数据报 Socket。Socket 工作原理:要通过互联网进行通信,你至少需要一对 Socket,其中一个运行于客户机端,我们称之为 ClientSocke
20、t,另一个运行于服务器端,我们称之为 ServerSocket。根据连接启动的方式以及本地 Socket 要连接的目标,Socket 之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。所谓服务器监听,是服务器端 Socket 并不定位具体的客户端 Socket,而是处于等待连接的状态,实时监控网络状态。所谓客户端请求,是指由客户端的 Socket 提出连接请求,要连接的目标是服务器端的Socket。为此,客户端的 Socket 必须首先描述它要连接的服务器的 Socket,指出服务器端 Socket的地址和端口号,然后就向服务器端 Socket 提出连接请求。所谓连接确认,是指
21、当服务器端 Socket 监听到或者说接收到客户端 Socket 的连接请求,它就响应客户端 Socket 的请求,建立一个新的线程,把服务器端 Socket 的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端 Socket 继续处于监听状态,继续接收其他客户端 Socket 的连接请求。TcpListener 和 TcpClient TcpClient 类是基于 TCP 协议的客户端类,而 TcpListener 是服务器端,监听(Listen)客户端传来的连接请求。TcpClient 类通过 TCP 协议与服务器进行通讯并获取信息,它的内部封装了一个 Socket 类的实
22、例,这个 Socket 对象被用来使用 TCP 协议向服务器请求和获取数据。因为与远程主机的交互是以数据流的形式出现的,所以传输的数据可以使用 framework 中流处理技术读写。多线程 操作系统使用进程将它们正在执行的不同应用程序分开。线程是操作系统分配处理器时间的基本单元,并且该进程中可以有多个线程同时执行代码。每个线程都维护异常处理程序、调度优先级和一组系统用于在调度该线程前保存线程上下文的结构。线程上下文包括为使线程在线程的宿主进程地址空间中无缝地继续执行所需的所有信息,包括线程的 CPU 寄存器组和堆栈。.NET 框架将操作系统进程进一步细分为由 表示的称为应用程序域的轻量托管子进
23、程。一个或多个托管线程(由 表示)可以在同一个非托管进程中的一个或任意数目的应用程序域中运行。虽然每个应用程序域都是用单个线程启动的,但该应用程序域中的代码可以创建附加应用程序域和附加线程。其结果是托管线程可以在同一个非托管进程中的应用程序域之间自由移动。支持抢先多任务处理的操作系统可以创建多个进程中的多个线程同时执行的效果。它通过以下方式实现这一点:在需要处理器时间的线程之间分割可用处理器时间,并轮流为每个线程分配处理器时间片。当前执行的线程在其时间片结束时被挂起,而另一个线程继续运行。当系统从一个线程切换到另一个线程时,它将保存被抢先的线程的线程上下文,并重新加载线程队列中下一个线程的已保
24、存线程上下文。时间片的长度取决于操作系统和处理器。由于每个时间片都很小,因此即使只有一个处理器,多个线程看起来似乎是在同时执行。要提高对用户的响应速度并且处理所需数据以便几乎同时完成工作,使用多个线程是一种最为强大的技术。在具有一个处理器的计算机上,多个线程可以通过利用用户事件之间很小的时间段在后台处理数据来达到这种效果。例如,在另一个线程正在重新计算同一应用程序中的电子表格的其他部分时,用户可以编辑该电子表格。在 C#中,名称空间提供了对多线程编程的支持,ThreadPool 类可以管理同时存在的一组线程,Mutex 类解决线程同步的问题,还有其它的一些类,可以解决多线程编程中遇到的各种问题
25、,像死锁(两个线程都停止响应,并且都在等待对方完成)和争用条件(由于意外地出现对两个事件的执行时间的临界依赖性而发生反常的结果)等等。实现步骤 5.4.1 步骤 1-建立程序框架 本实例是控制台程序,在 File-New-Project 内选择建立 C#Cosole Application,名为 ftpd,如图 5-8 所示。工程建立之后,在 Solution Explorer 中将系统为我们建立的默认类文件改名为,并把该文件中原来的所有内容删掉。建立我们自己的名称空间,添加引用:namespace using System;using;using;using ;在这个例子中,我们要创建的类有
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ftp 服务器 详解 源代码
限制150内