收藏 分销(赏)

FTP服务器-详解+源代码.doc

上传人:人****来 文档编号:3367725 上传时间:2024-07-03 格式:DOC 页数:44 大小:305KB
下载 相关 举报
FTP服务器-详解+源代码.doc_第1页
第1页 / 共44页
FTP服务器-详解+源代码.doc_第2页
第2页 / 共44页
FTP服务器-详解+源代码.doc_第3页
第3页 / 共44页
FTP服务器-详解+源代码.doc_第4页
第4页 / 共44页
FTP服务器-详解+源代码.doc_第5页
第5页 / 共44页
点击查看更多>>
资源描述

1、一个简单的FTP服务器实例目标FTP是网络上共享资源的常用方法,在本章中我们将实现一个简单的FTP服务器。本章知识点:l FTP协议l Socket类和TcpListener类l System.Threading 名称空间5.1 实例功能本实例实现一个简单的FTP服务器,该服务器是一个控制台程序,编译后的可执行文件为ftpd.exe,在控制台中键入ftpd后就可启动服务器,若要改变ftp服务器的工作目录,可以键入ftpd r 后接绝对路径。服务器的ftp服务端口采用默认的21。服务器启动后,用户就可从其他任何一台联网计算机进行访问。下面是应用的一个例子:(服务器所在机器的ip为166.111.

2、147.25)用户在自己计算机的控制台中输入ftp 166.111.147.25 回车后可以看到服务器传过来的欢迎信息,并要求输入登陆账号(图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

3、 服务端运行情况5.2 编程思路要实现FTP服务器,我们必须对FTP协议有一定的了解,使用符合协议的指令集和网络传输方式,我们将在下一节详细介绍关于FTP协议的基础知识。另外,我们还采用了TcpListener和Socket编程技术实现数据传输,所以这也是我们需要掌握的内容。最后,为了同时给多个用户提供服务,FTP服务器还必须支持多线程。FTP服务器程序的大框架是这样的:程序运行后,在服务器的某个端口有一个TcpListener一直在监听用户的请求,当有用户请求服务时,服务器立刻创建一个新的线程处理这个请求,我们称开始了一个新的会话。在会话中,服务器通过Socket接收用户命令,对命令进行分析

4、后采取相应的操作,并将结果返回。一直到用户退出这个会话,服务器才销毁这个线程。服务器和客户端的会话方式有两种,一是被动方式(passive),即服务器在某个特定端口有一个TcpListener在不断监听用户命令;二是主动方式,这种情况下,服务器在该客户端有服务请求时,创建一个套接字和它进行数据传输。5.3 关键技术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命令指定数据连接参数和文件系统操作。用户DTP在特定数据端口侦听,服务器开始数据连接并以指

7、定的参数开始数据传输。数据端口不必在开始FTP命令的机器上,但用户或用户FTP进程必须确定它在指定的数据端口上侦听。这个数据连接是全双工的。在另外一种情况下,用户或许希望在两个主机间传送文件,不是两个本地主机。用户在两台主机间建立控制连接,然后规划数据连接。用这种方式,控制信息由用户PI获得,但是数据在服务器DTP之间传送。图5-7就是一个例子:图5-7协议要求数据传输在处理时打开控制连接。在完成FTP服务后由用户中止控制连接,而服务器具体操作。如果在未接收命令时关闭了控制连接,服务器也会关闭数据传输。数据传输功能数据连接只传输数据,控制连接传送命令和响应。几个命令是关于在主机间传输数据的,数

8、据传输基本上独立于物理结构的,但是如果在压缩传输模式下流式传输与文件结构有关,文件的属性与表示类型有关。q 数据表示与保存数据是在主机间的存储设置间传送的。因为两个系统的数据存储方式不同,因此需要对它进行转换,在传送文本时会有对ASCII表示的问题,在进行二进制传送的时候,会有不同系统对字节长度规定不同的问题,有的系统是7位,有的系统可能是32位,这也需要进行转换。需要提供数据表示与传输模型函数,但是FTP提供这方面的功能不多,超过FTP提供功能的那一部分要用户自己实现。数据表示是由用户指定的表示类型,它可以是隐含的,也可以是用户指定的。请一定注意:逻辑字节长度与物理字节长度是不同的。ASCI

9、I类型:这是所有FTP必须实现的默认类型,用于传送文本文件,当在主机间使用EBCDIC传送时更方便,则不使用ASCII类型。发送方将内部表示转换为NVT-ASCII格式,接收方则进行相反的过程接收数据。根据NVT标准,要在行结束处使用序列。NVT-ASCII是8位的。ASCII和EBCDIC的格式参数在下面讨论。EBCDIC类型:它是作为ASCII的另一种方法在主机间传送数据的数据类型。EBCDIC和ASCII很象,仅在类型的功能描述上有一些差别。行结束符使用很少。图象类型:在此类型下传送的数据被看作连续的位,发送方将数据打包到8位传输字节中传送。因为结构的需要要对传送数据进行填充,填充字节全

10、部为0,填充必须在文件结构时使用,而且要标记出以便接收方过滤掉。它用于传送二进制数据和有效地传送和存储文件,因此所有FTP也必须实现。本地类型:也可以以十进制指定逻辑字节大小。如果物理字节大小和逻辑字节大小不同,直接将物理数据打包为逻辑字节,不用什么填充。接收方根据逻辑字节大小进行和本机的存储特点进行转换。传输必须是可重复的,也就是说,相同的文件相同的参数,那内容必须是一样的。数据结构除了有不同的数据类型外,FTP还允许有不同的文件结构,下面是三种文件结构:文件式结构:文件中没有内部结构,文件被看作是二进制流;记录结构:文件是由一系列记录组成的;页结构:文件是由不同的索引页组成的。如果未使用S

11、TRU命令,文件结构是默认值。文件的结构会影响传输模型,存储和数据表示。文件本来的属性和保存它的主机有关,不同的机器会以自己的方式保存文件。在不同主机间传送文件时必须使主机能够识别相互的表示。有些主机上的文件是面向字节的,有些是面向记录的,在传送时就会出现问题。那就要在接收方进行内部转换。在进行转换的时候,需要区别记录的边界,在ASCII中使用,在EBCDIC中使用作为分隔符。采用这种实现方法的必须保证转换是可逆的。文件结构:如果未使用STRU命令,文件结构是默认值。文件结构中没有默认值,文件被看作是连续的字节串。记录结构:对于文本文件,记录结构必须是所有FTP实现必须有的。记录结构文件是由连

12、续的记录构成的。页结构:文件是非连续时使用页结构。这种文件称为随机访问文件。这些文件中有时会的和文件整体或部分相关的信息出现。在FTP中,文件的一个部分称为页。建立数据连接传送数据机制包括建立连接选择数据参数。用户和服务器DTP有默认数据端口。用户进程默认数据端口和控制连接端口相同。服务器进程默认数据端口和控制连接端口相邻。传输字节大小是8位字节。此字节是实际传输字节,但不代表主机内的数据表示。被动数据传输进程在数据端口接收数据,FTP请求命令决定数据传输的方向。服务器在接收到请求以后,将初始化端口的数据连接。当连接建立后,传输在DTP之间传送,服务器PI对用户PI返回应答。FTP实现运行一个

13、默认数据端口,用户PI才能改变默认端口。通过PORT命令可能改变端口,用户可能希望数据在第三方主机上进行其它操作,用户PI需要在两个服务器PI上建立连接。一个服务器被告知侦听另一服务器的请求。用户PI通过PORT命令通知另一服务器的数据端口。最后双方发送相应的传送命令。通常,服务器负责支持数据连接,初始化并关闭它,除非用户DTP在传输模式下要求关闭连接。服务器在下面情况下关闭数据连接:q 服务器结束发送数据,通过EOF要求中止传送;q 用户发送ABORT命令;q 用户改变端口;q 控制连接关闭;q 发生不可恢复错误。数据连接管理默认数据连接端口:所有FTP必须支持默认数据连接,只有用户PI能够

14、初始化非默认端口的使用。确定非默认数据端口:用户PI可以使用PORT命令指定非默认端口,它要求服务器方以PASV确定非默认数据端口。连接是由双方地址确定的,因此改变一方地址就改变了连接。数据连接的重用:在使用流式数据传输模型时,文件结束通过关闭连接指示。如果要传送多个文件时就会出麻烦,解决的方法有两个,一个是确定非默认端口,另一个是使用另一种传输模式。就传输模式而言,流传输模式是不安全的,因此无法确定连接是暂时还是永久关闭。其它传输模式不通过关闭连接表示文件结构,它们可以通过FTP命令决定传送结构。因此使用这些传输模式可以在保持连接的情况下传送多个文件。传输模式有三种传输模式:一种将数据格式化

15、并考虑重新开始过程;一种压缩数据;一种是不经过处理(少量处理)传送。所有数据传输必须以一个EOF结束,它可以显式给出,也可以通过关闭连接隐式给出。对于记录文件,所有EOR是显式的,包括最后一个记录。对于以页结构传送的文件,使用“最后一页”表示结束。从这里开始,下文中我们提到的字节指的是“传输字节”。为了进行标准化传送,传送主机必须把行结束或记录结束的内部表示转化为传输模式和文件结构指定的形式传送,接收方则进行相反的工作。IBM大型机的记录计数域可能不能为其它主机识别,所以记录结束标记在流模式下以双字节控制码传送,在块或压缩模式下以标记位传送。而ASCII或EBCDIC的行结束则则或指示。这样的

16、转换需要时间,所以相同的系统在传送文本文件时采用二进制或流表示比较合适。下面是FTP定义的传输模式:流模式:数据以字节流的形式传送。使用的表示类型没有限制,允许记录结构。在记录结构文件EOR和EOF表示为双字节控制码。第一字节全为0,后一字节为转义字符。当第二位值为1时表示EOR,为2时表示EOF,如果要同时表示EOR和EOF,值为3。全1字节作为数据发送时必须使用双字节传送,其中数据保存在第二个字节内。如果是文件结构,通过发送方关闭连接表示EOF,接收到的所有数据就是文件内容。块模式:文件以块形式传送,块带有自己的头部分。头字节包括计数域和描述子代码。关于FTP协议的基本知识我们先介绍这些,

17、在以后的代码分析中我们将结合实例,做更深入的讨论。基于TCP协议的网络通讯TCP协议是一个基本的网络协议,基本上所有的网络服务都是基于TCP协议的,FTP也是,所以必须了解基于TCP协议的编程。然而TCP协议是一个庞杂的体系,要彻底的弄清楚它的实现不是这么容易,不过在.NET Framework环境下,我们不必要去追究TCP协议底层的实现,一样可以很方便的编写出基于TCP协议进行网络通讯的程序。在这章里,我们主要通过两个类编写FTP服务程序,这两个类是:TcpListener类和Socket类,它们都属于System.Net.Sockets名称空间。q Socket类简介Socket(套接字)

18、是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。可以将Socket看作不同主机间的进程进行双向通信的端点,它构成了单个主机内及整个网络间的编程界面。Socket存在于通信域中,通信域是为了处理一般的线程通过Socket通信而引进的一种抽象概念。Socket通常和同一个域中的Socket交换数据(数据交换也可能穿越域的界限,但这时一定要执行某种解释程序)。各种进程使用这个相同的域互相之间用Internet协议簇来进行通信。 Socket可以根据通信性质分类,这种性质对于用户是可见的。应用程序一般仅在同一类的Socket间进行通信。不过只要底层的通信协议允许,不同类型的Socket间

19、也照样可以通信。Socket有两种不同的类型:流Socket和数据报Socket。Socket工作原理:要通过互联网进行通信,你至少需要一对Socket,其中一个运行于客户机端,我们称之为ClientSocket,另一个运行于服务器端,我们称之为ServerSocket。根据连接启动的方式以及本地Socket要连接的目标,Socket之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。 所谓服务器监听,是服务器端Socket并不定位具体的客户端Socket,而是处于等待连接的状态,实时监控网络状态。所谓客户端请求,是指由客户端的Socket提出连接请求,要连接的目标是服务器端的S

20、ocket。为此,客户端的Socket必须首先描述它要连接的服务器的Socket,指出服务器端Socket的地址和端口号,然后就向服务器端Socket提出连接请求。所谓连接确认,是指当服务器端Socket监听到或者说接收到客户端Socket的连接请求,它就响应客户端Socket的请求,建立一个新的线程,把服务器端Socket的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端Socket继续处于监听状态,继续接收其他客户端Socket的连接请求。q TcpListener和TcpClientTcpClient类是基于TCP协议的客户端类,而TcpListener是服务器端,监听

21、(Listen)客户端传来的连接请求。TcpClient类通过TCP协议与服务器进行通讯并获取信息,它的内部封装了一个Socket类的实例,这个Socket对象被用来使用TCP协议向服务器请求和获取数据。因为与远程主机的交互是以数据流的形式出现的,所以传输的数据可以使用.net framework中流处理技术读写。多线程操作系统使用进程将它们正在执行的不同应用程序分开。线程是操作系统分配处理器时间的基本单元,并且该进程中可以有多个线程同时执行代码。每个线程都维护异常处理程序、调度优先级和一组系统用于在调度该线程前保存线程上下文的结构。线程上下文包括为使线程在线程的宿主进程地址空间中无缝地继续执

22、行所需的所有信息,包括线程的CPU寄存器组和堆栈。.NET 框架将操作系统进程进一步细分为由 System.AppDomain 表示的称为应用程序域的轻量托管子进程。一个或多个托管线程(由 System.Threading.Thread 表示)可以在同一个非托管进程中的一个或任意数目的应用程序域中运行。虽然每个应用程序域都是用单个线程启动的,但该应用程序域中的代码可以创建附加应用程序域和附加线程。其结果是托管线程可以在同一个非托管进程中的应用程序域之间自由移动。支持抢先多任务处理的操作系统可以创建多个进程中的多个线程同时执行的效果。它通过以下方式实现这一点:在需要处理器时间的线程之间分割可用处

23、理器时间,并轮流为每个线程分配处理器时间片。当前执行的线程在其时间片结束时被挂起,而另一个线程继续运行。当系统从一个线程切换到另一个线程时,它将保存被抢先的线程的线程上下文,并重新加载线程队列中下一个线程的已保存线程上下文。时间片的长度取决于操作系统和处理器。由于每个时间片都很小,因此即使只有一个处理器,多个线程看起来似乎是在同时执行。要提高对用户的响应速度并且处理所需数据以便几乎同时完成工作,使用多个线程是一种最为强大的技术。在具有一个处理器的计算机上,多个线程可以通过利用用户事件之间很小的时间段在后台处理数据来达到这种效果。例如,在另一个线程正在重新计算同一应用程序中的电子表格的其他部分时

24、,用户可以编辑该电子表格。在C#中,System.Threading名称空间提供了对多线程编程的支持,ThreadPool类可以管理同时存在的一组线程,Mutex类解决线程同步的问题,还有其它的一些类,可以解决多线程编程中遇到的各种问题,像死锁(两个线程都停止响应,并且都在等待对方完成)和争用条件(由于意外地出现对两个事件的执行时间的临界依赖性而发生反常的结果)等等。5.4 实现步骤5.4.1 步骤1-建立程序框架本实例是控制台程序,在File-New-Project内选择建立C# Cosole Application, 名为ftpd,如图5-8所示。工程建立之后,在Solution Expl

25、orer 中将系统为我们建立的默认类文件Class1.cs改名为ftpd.cs, 并把该文件中原来的所有内容删掉。建立我们自己的名称空间,添加引用:namespace FTPD.NETusing System;using System.IO;using System.Net;using System.Net.Sockets;using System.Threading;在这个例子中,我们要创建的类有:主程序类MainApp,负责启动服务器,是程序运行的入口;Ftpd类,创建服务线程,处理用户请求,最主要的工作在这里完成。SessionInfo类,用于管理会话;另外我们还有一个PassiveIn

26、fo结构,用于管理被动模式下的连接设置。后面两个数据类型非常简单,只含有若干数据项,而没有任何方法。图5-8 创建工程5.4.2 步骤2-实现MainApp步骤描述启动FTP服务器,用户可以设置FTP服务的目录。功能实现在ftpd.cs文件中加入下面的代码: public class MainApp public const String Version = 0.0.1; public static String szFtpRoot = E:incoming; public static bool fDebug = true; /服务器管理界面: public static void Usag

27、e( ) Console.WriteLine(ftpd usage:); Console.WriteLine(); /改变ftp目录 Console.WriteLine(-r patht:tSpecifies FTP Root); /帮助 Console.WriteLine(-? t:tPrints this help); return; public static int Main( String Arguments ) for( int i = 0; i Arguments.Length; i+ ) switch( Arguments i ) /设定ftp目录 case -r: szFtp

28、Root = Arguments i + 1 ; break; case -?: Usage(); return 0; default:/无参数运行时ftp目录设为当前目录 szFtpRoot = Directory.GetCurrentDirectory(); break; /创建一个Ftpd对象实例 Ftpd pFtpd = new Ftpd(); /启动ftp服务 if( pFtpd.StartServer() = false ) Console.WriteLine( Failed to start FTP Server. ); return -1; return 0; 代码分析Main

29、()函数的有两种参数形式:无参数和string 数组表示的命令行参数,即static void Main()或static void Main(stringargs) ,后者接受命令行参数,并且将用户输入的参数放到args字符数组中(程序名称不算是第一个参数,这一点和VC+不同)。在我们的程序里,我们首先对命令行参数进行分析,如果第一个参数是-r 则将第二个参数读入做为用户指定的FTP服务目录,如果第一个参数是-?,则显示调用函数usage(),显示帮助信息。如果没有参数,则将当前目录设为FTP的目录,在这里,我们使用静态类Directory的GetCurrentDirectory()方法得到

30、当前工作目录:szFtpRoot = Directory.GetCurrentDirectory();Directory类属于System.IO名称空间,提供了有关移动,创建目录,返回本目录下文件和子目录等的方法。public sealed class Directory由于它是静态类,所以我们不必实例化就可以直接调用它的方法。它的函数方法有:1) public static DirectoryInfo CreateDirectory( string path);path参数为要建立的目录名,下面是一些合法目录名的例子:c:MyDir ,c:MyDir, MyDirMySubdir, MySe

31、rverMyShare。而像c:temp”,”c:windows 则是不合法的。方法返回一个DirectoryInfo类对象,DirectoryInfo类和Directory类的区别只在于,前者的方法都不是静态方法,必须实例化后才能调用它的函数,但它和Directory类一样可以创建,移动,浏览目录。2) public static void Delete(string);删除指定的空目录;3) public static void Delete(string,bool);如果第二个参数为True,则删除该目录下所有的文件和子目录,否则只删除文件。4) public static string

32、 GetCurrentDirectory();返回当前的工作目录。5) public static string GetFiles(string);public static string GetFiles(string, string);前者返回指定目录下所有的文件的名称,放到一个string数组中。后者查找指定目录下(目录名为第一个参数)文件名含有第二个参数字符串的所有文件的名称。6) public static string GetDirectories(string);public static string GetDirectories(string, string);前者返回指定目

33、录下所有子目录的名称,放到一个string数组中。后者查找指定目录下(目录名为第一个参数)目录名含有第二个参数字符串的所有子目录的名称。7) public static DirectoryInfo GetParent(string path);返回指定目录的上一级目录的DirectoryInfo对象。8) public static void Move(string sourceDirName, string destDirName);将指定的目录下所有的内容移到新目录下。9) public static void SetCurrentDirectory(string path);设定当前工作

34、目录为指定目录。程序分析完命令行参数后,创建了一个FTPD对象,下一节我们看FTPD对象是如何工作的。5.4.3 步骤3-FTPD类主框架步骤描述程序创建一个FTPD类对象后,该对象监听来自用户的服务请求,并为每个请求创建线程,提供服务,下面我们建立它的主框架。功能实现在ftpd.cs文件中创建ftpd类,并加入下面代码:public Ftpd()/实例化一个在端口21监听的TCPListenerTCPListener = new TcpListener(21);/开始服务public bool StartServer()try/开始监听TCPListener.Start();/循环while

35、( true )/接收客户端的一个连接请求,返回一个套接字s = TCPListener.AcceptSocket();/创建一个线程,处理当前连接Thread client = new Thread( new ThreadStart( ServeConnection ) );/线程开始运行client.Start();catch( SocketException Se )DBG_TRACE( An Socket Class Exception Has Occured );DBG_TRACE( Error: 0, Se.ErrorCode );return false;代码分析在ftpd类的构

36、造函数内我们创建了一个TcpListener对象,TcpListener类属于System.Net.Sockets名称空间,建立在Socket类之上,为HTTP、FTP等应用层软件提供基于TCP协议的网络通讯方法。它的构造函数原型是:(1)public TcpListener(int);(2)public TcpListener(IPEndPoint);(3)public TcpListener(IPAddress, int);构造函数(1)在本机指定端口监听用户的连接请求。构造函数(2)在指定的IPEndPoint上监听请求,IPEndPoint类描述计算机上的一个EndPoint, 包括它

37、的IP地址和端口。构造函数(3)在指定IP和端口上监听请求,下面是一个例子:IPAddress ipAddress = Dns.Resolve(localhost).AddressList0;try TcpListener tcpListener = new TcpListener(ipAddress, 13); catch ( Exception e) Console.WriteLine( e.ToString();在我们的例子里,我们在FTP的默认端口21上监听:TCPListener = new TcpListener(21);TcpListener类只有一个属性:public EndP

38、oint LocalEndpoint get;可以通过它得到该TcpListener所在的IP地址和端口。TcpListener类主要方法有:1)public Socket AcceptSocket();返回一个Socket对象,可以利用该对象和远程计算机发送和接收数据,这个对象的IP地址和端口号是由远程计算机初始化的。2)public TcpClient AcceptTcpClient();返回一个TcpClient对象,可以通过它发送和接收数据。我们可以调用TcpClient的GetStreem方法,得到这个连接的NetworkStream对象,NetworkStream类继承自Strea

39、m类,提供了一系列方法处理通讯过程中传递的数据。3)public void Start();Start方法被调用后,TcpListener实际上做了下面两件事情:q 把自己的LocalEndpoint和底层的Socket对象绑定起来。q 调用底层的Socket对象的Listen方法,开始监听来自客户端的请求。public void Stop();停止监听请求,关闭底层的Socket对象。在上一节MainApp类的Main函数里,我们最后调用了ftpd的StartServer方法,开启ftp服务,下面我们看这个函数具体做了什么。首先,开始监听21端口:TCPListener.Start();然后

40、是一个无限循环,处理来自不同用户的请求,while( true )在循环体内,先调用TcpListener的AcceptSocket方法,获得与用户通讯的Socket对象(注意,如果开始时没有用户请求,程序将停在此处,而不是往下继续执行)。这个Socket对象,是处理和用户的控制连接的。在FTP协议里,我们将与用户的连接分为控制连接和数据连接两种,关于这部分的详细说明,读者可以参看前面的“关键技术”一节。在获得Socket对象后,我们创建了一个新的线程来处理这个用户的请求,Thread client = new Thread( new ThreadStart( ServeConnection

41、) );client.Start();Thread类属于System.Threading名称空间,所有与多线程机制应用相关的类都是放在System.Threading命名空间中的。其中提供Thread类用于创建线程,ThreadPool类用于管理线程池等等,此外还提供解决了线程执行安排,死锁,线程间通讯等实际问题的机制。Thread类有几个至关重要的方法,简单介绍一下:Start():启动线程。Sleep(int):静态方法,暂停当前线程指定的毫秒数。Abort():通常使用该方法来终止一个线程。Suspend():该方法并不终止未完成的线程,它仅仅挂起线程,以后还可恢复。 Resume():

42、恢复被Suspend()方法挂起的线程的执行。使用Thread类创建线程时,只需提供线程入口即可。线程入口使程序知道该让这个线程干什么事,线程入口是通过委托(delegate)ThreadStart来提供的,它的原型是:Serializablepublic delegate void ThreadStart();当调用Thread.Start()方法后,线程就开始执行ThreadStart所代表或者说指向的函数。我们在例子里创建了委托TreadStart的一个实例:new ThreadStart( ServeConnection )ServerConnection是我们将要编写的一个函数,在下

43、一节里我们将要谈到。这里要明确的是,它的参数列表和返回值都和委托ThreadStart一致。然后我们把这个委托的实例作为Thread对象构造函数的参数创建了一个Thread对象。Thread类的构造函数原型是:public Thread(ThreadStart start);Thread对象被创建后,线程并没有马上开始,我们必须调用它的Start方法:client.Start();在这个例子里,我们并没有用到关于多线程编程或者说Thread类的更多内容。不过,下面介绍的关于这方面的扩展内容也许对读者有所用处。我们从Thread.ThreadState属性说起,这个属性代表了线程运行时状态,在不

44、同的情况下有不同的值,于是我们有时候可以通过对该值的判断来设计程序流程。ThreadState在各种情况下的可能取值如下:Aborted:线程已停止。AbortRequested:线程的Thread.Abort()方法已被调用,但是线程还未停止。Background:线程在后台执行,与属性Thread.IsBackground有关。Running:线程正在正常运行。Stopped:线程已经被停止。StopRequested:线程正在被要求停止。Suspended:线程已经被挂起(此状态下,可以通过调用Resume()方法重新运行)。SuspendRequested:线程正在要求被挂起,但是未来

45、得及响应。Unstarted:未调用Thread.Start()开始线程的运行。WaitSleepJoin:线程因为调用了Wait(),Sleep()或Join()等方法处于封锁状态。上面提到的Background状态表示该线程在后台运行,那么后台运行的线程有什么特别的地方呢?其实后台线程跟前台线程只有一个区别,那就是后台线程不妨碍程序的终止。一旦一个进程所有的前台线程都终止后,CLR(通用语言运行环境)将通过调用任意一个存活中的后台进程的Abort()方法来彻底终止进程。当线程之间争夺CPU时间时,CPU按照是线程的优先级给予服务的。在C#应用程序中,用户可以设定5个不同的优先级,由高到低分别是Highest,Above

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服