Login
升级VIP 登录 注册 安全退出
当前位置: 首页 > word文档 > 其他文档 > 基于java的远程登录和文件传输功能的实现

基于java的远程登录和文件传输功能的实现

收藏

本作品内容为基于java的远程登录和文件传输功能的实现,格式为 doc ,大小 5115392 KB ,页数为 55页

基于java的远程登录和文件传输功能的实现


('基于java的远程登录和文件传输功能的实现摘要Internet发展至今产生了两种比较重要的网络体系结构:ISO/OSI和TCP/IP参考模型,ISO/OSI模型有7层:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。而TCP/IP模型只有4层:主机至网络层,互连网层,传输层,应用层。其中TCP/IP参考模型中的应用层包含所有的高层协议,最早引入的是虚拟终端协议,文件传输协议和电子邮件协议。本文对网络计算机相互通信的机理进行比较细致和深入的分析并采用java编程工具实现了远程登录和文件传输的功能。关键词:TCP/IPJAVA远程登录文件传输AbstractInternetproducestwokindsofmoreimportantnetworksystemstructuresofarthatInternetisdeveloped,ISO/OSIandTCP/IPconsultmodels,ISO/OSImodelis7layers:Physicslayer,datalinklayer,networklayer,transportlayer,sessionlayer,persentaltionlayer,opplicationlayer.AndTCP/IPmodelis4layers:FromhostcomputertoInternet,networklayer,transportlayer,opplicationlayer.TCP/IPamongthemconsultapplicationlayerofmodelincludeallontheseniorlevelProtocol,introduceTELecommunicationsNETwork,FileTransferProtocolandSimpleMailTransferProtocol,Carefulanddeepanalysisthatthistextcomparesmechanismthatthenetworkcomputercommunicateseachother,andadoptjavaprogrammingtooltorealizethefunctionsoftelecommunicationsnetworkandfiletransfer.KEYWORDS:TCP/IPJAVATELNETFTP目录前言--------------------------------------------------------------------------------------------1第一章互联网概述----------------------------------------------------------------------31.1互联网的发展状况--------------------------------------------------------------------31.2互联网的应用-------------------------------------------------------------------------5第二章互联网中两种重要的参考模型-----------------------------------------------62.1OSI参考模型-------------------------------------------------------------------------62.2TCP/IP参考模型--------------------------------------------------------------------8第3章远程登录的功能实现----------------------------------------------------------------93.1虚拟终端-------------------------------------------------------------------------------93.2远程登录协议--------------------------------------------------------------------------113.3有关远程登录的实现方法(线程的概念)---------------------------------------133.4远程登录的最终完成---------------------------------------------------------------18第4章文件传输的执行行为和功能------------------------------------------------------274.1传输文件--------------------------------------------------------------------------------274.2文件传输的传输模式----------------------------------------------------------------284.3构造控制连接和数据连接------------------------------------------------------------324.4文件传输程序的完成-----------------------------------------------------------------42第5章总结----------------------------------------------------------------------------------53参考文献---------------------------------------------------------------------------------------54谢辞----------------------------------------------------------------------------------------55前言历史的发展表明Internet的产生要追溯到最开始的时间,穴壁上的画、烟信号驿站—所有这些通信方式都使我们的祖先一直在考虑一个更好的通信方式。接着就发展出了电报、电话、无线电—现在这些东西随处可见。在这之后,计算机出现了,那时,最大最耗电,并产生大量热的计算设备也比不上现在最小的掌上计算器,这些大家伙当时用于赢得战争和人口普查,但当时计算机的数量极少,也很少有人买得起,况且还需要很多房间装下它们。今天,Internet已经发展得更加商业化,更加面向消费者,尽管基本目的发生了改变,但其最初的所有质量标准(也就是开放式、抗毁性和可靠性)依然是必需的这些特性包括可靠传输数据、自动检测和避免网络发生错误的能力。更重要的就是TCP/IP是一个开放式通信协议,开放性意味着在任何组合间,不管这些设备的物理特征有多大差异,都可以进行通信。毫无疑问,TCP/IP(通常它是指传输控制协议/网际协议,TransmissionControlProtocol/InternetProtocol)是发展至今最成功的通信协议,它被用于当今所构筑的最大的开放式网络系统Internet之上就是其成功的明证。Internet最初的设计是为了满足美国国防的需要,具体来讲就是使美国政府即使在遭受核打击时也能保证通信不间断,TCP/IP就是用于这个目的的。正是TCP/IP使得Internet发展到今天这个状态,随后,Internet正像它的“革命先驱者”,如打印机、电和计算机一样改变了我们生活和工作的方式。如果没有诸如HTTP、SMTP、TELNET和FTP这些流行的协议和服务,Internet不会比一个由大量计算机所连成毫无价值的节点强多少。本文将比较详细介绍流行的Internet协议中的两种远程登录和文件传输功能实现方法。第一章互联网概述1.1互联网的发展状况10年来,互联网在风中一路飘摇,舆论像是骑在墙头上的看客,用各种各样东倒西歪的姿势见证着一切,用各种各样慷慨激昂、不着边际的语言谈论着一切。从文化和社会学的某种角度看,现代化在中国一直是一个有意思的历史过程;而当第二次现代化与第一次现代化交织在一起,在中国这样一个半封闭社会当中含混其辞、跌跌闪闪地匍匐前进的时候,农民式的市民,在目光、内心和行为举止当中尤其充满了荒诞。互联网这么一个不是东西的东西,太容易成为第三世界公民们的谈资。过去有关互联网的报道、分析和评论,很多在开口的一刹那很可能就已经是错误的,现在也是如此。诸多无比经典的荒诞,无需太多讨论和佐证,因为无数的无知和短视行为最终已经被各种各样的事实证明:它们而不是互联网,是错误的。互联网一直以它自己的方式进行着,它一直在那儿。历史的荒原经常风云突变,互联网一直是预言中的下一个重大事件,但是我们能够目睹到的似乎一直都是一个又一个或明或暗的瞬间。就像我们曾经感触到、不曾感觉到的很多关于互联网的变化一样,互联网的到来是一个若隐若现、动态变幻的历史过程。没有绝对的开启点,也没有绝对的终结点。互联网发展进程的切换也好,互联网与传统产业的结合也好,互联网自身的不断创新和扩展也好,都是这个动态的历史过程的不是片段的片段。我们不知道互联网从哪里来,因为互联网没有确定的、唯一的源头;我们也不知道互联网将会向哪里去,因为迄今为止我们并不了解互联网的全部,而且我们也还没有看到互联网的全部。互联网只是呈现出它在今天所初步呈现出来的这个样子。今天的互联网,不是互联网的全部。互联网,也不是那个“重大事件”的全部。那个重大事件正在把我们带向哪里?我们正在把互联网带向何方?或者更准确地讲,互联网将会把我们带向何方?如果说作为重大事件一个不是片段的片段的互联网的历史才刚刚开始,如果说在2004年昔日充满荒诞与喧嚣的狂飙突进的网络运动已经告一段落,网络部落的大队人马走过蛮荒之地,那么,眼前到来的,是否就是亚马逊平原?2004年,没有人知道互联网的全部,没有人知道关于互联网的所有答案。而且,我们其实仍然不是非常确切地知道互联网是不是一种技术,或者说并不是一种技术,或者说是技术的商业,抑或是商业的技术。或者说,是一种生产力,还是一种生产关系?是技术的制度,还是制度的技术?所以,互联网对于我们的社会,互联网关于技术、资本、财富、商业的启蒙已经结束了吗,或者是还没有结束?互联网是经常被我们借用的符号意义上的“他者”,还是正在到来的下一个重大事件所驱动的变革的主体?或者仅仅只是阶段性的主题?这些问题,都是需要回答的未解之题。所以,2004年,关于互联网,我们不要急于做出这样那样的判断,迫切宣告这样那样的结论。互联网没有结束,所以互联网没有结论。2004年,在中国互联网全功能接入国际互联网10周年庆典仪式刚刚隆重举行的这个时候,我们不要四处遗撒关于互联网的种种大词汇。所谓10年,是我们自己给互联网定义的一个只属于我们自己的仪式。互联网一直以它自己的方式进行着,它一直在那儿。它并没有因为这个仪式而有任何改变。互联网的发展是开放的,过去是开放式的,现在是开放式的,未来更是开放式的。迄今为止,关于互联网的所有定义都是暂时的。所以,说我们不知道,比说我们知道要好得多。因为,极有可能在说知道的那一瞬间,我们对于互联网的认知已经步入了歧途。所以,真正想要说的是:在第二次启蒙、互联网的第二次发展热潮到来之前,让我们对自己的思想来一次非常理性的清零。2004,我们重新出发。而且,我们必须承认,到现在为止,我们并不是特别了解互联网。也只有这样彻底的清零,彻底抛弃关于互联网的种种成见、偏见和意见,在2004年,我们才可能重新出发,正确地出发,正确面对我们自己为自己定义的互联网的下一个10年。1.2互联网的应用从90年代开始,计算机网络开始为居家的个人用户提供服务。下面简要的介绍方兴未艾的最激动人心的3种服务:访问远程信息,个人间通信和交互式信息。访问远程信息有多种形式。一个常见的例子是访问财务部门。许多人现在用电子方式支付帐单,管理银行户头和进行投资。居家购物也开始流行,人们可以浏览成千上万的联机货物清单。某些清单还能很快提供相应产品的即时影响,只需轻轻一点该产品的名字就可以了。第二类应用是访问信息系统。比如当前世界范围内使用的万维网,它包含了有关艺术,商业,餐饮,政府,健康,历史,爱好,娱乐,科学,体育,旅游等方面的信息。以上所有应用都涉及到任何远程数据库的交互。网络的第二类广泛应用将使人际交互,基本上它是21世纪替代19时机发明的电话的手段。电子邮件或者说email,以在上百万人当中使用,并且将很快包含声音,图像,与文本一起传送。但这要花相当长的一段时间才能做到尽善尽美。再一群经选择的人之间使用世界范围的新闻组已是常事,他们在一起讨论各种可能的话题,并且有越来越多的公众参加进来。在讨论中,某人发表一篇文章,而其他订阅该新闻组的人就可阅读它,通常这种讨论很有趣也很热烈。第三类应用是娱乐,这是一个巨大并且还在继续增长的工业。这里最吸引人的应用是视频点播,它可能会把其他所有应用都赶出去。新电影可能会是交互式的,观众可以在某一时刻选择故事的发展方向而在拍摄时已经为各种可能的情节发展提供了场景。直播电视也肯恩硅会变成交互式的,观众将参与问答节目,选择竞赛者等。在另一方面,视频点播并不一定会成为主宰。游戏可能会使黑马。我们已经有了多人实时模拟游戏,如在虚拟地牢中玩捉迷藏,或者飞行模拟,一组玩家与另一组娃家对玩。如果能做到用头盔来玩,并由实施三维动作及图片质量的移动图像,我们就拥有了世界范围的共享虚拟现实。简单的说,综合信息,通信和娱乐的能力将造成一个新兴的,基于计算机网络的巨大工业。第二章互联网中两种重要的参考模型我们将重点介绍两个层次模型,正是这两个模型使的开放式数据通信成为可能。这两个模型是开放式系统互联(OpenSystemsInterconnect,OSI)参考模型和TCP/IP参考模型。这些模型通过将网络分为各种功能模块,从而大大提高了网络的可理解程度。这些模块被分为层。这些层次的命令以及开放通信的概念,为TCP/IP各种组件和使用的更广泛探索提供了场景和依据。2.1OSI参考模型国际标准化组织(ISO)开发了开放式系统互联(OSI)参考模型,以促进计算机系统的开放互联。开放式互联就是可在多个厂家的环境中支持互联。该模型为计算机间开放式通信所需要定义的功能层次建立了全球标准。该模型很成功地达到了它最初的目的:将它自己付诸讨论通过。至此,早先的专利极端集成方式已经消失了。今天,开放式通信是必需的,令人惊奇的是,很少有产品是完全的OSI模式;相反,其基本层次框架常常满足新标准。然而,OSI参考模型为示范网络的功能结构提供了可行的机制。OSI模型将通信会话需要的各种进程划分成7个相对独立的功能层次,这些层次的组织是以在一个通信会话中事件发生的自然顺序为基础的。1.物理层最底层称为物理层(PhysicalLayer),这一层负责传送比特流,它从第二层数据链路层(DDL)接收数据帧,并将帧的结构和内容串行发送即每次发送一个比特,然后这些数据流被传输给DLL重新组合成数据帧。2.数据链路层(DLL)OSI参考模型的第二层称为数据链路层(DLL)。与所有其他层一样,它肩负两个责任:发送和接收。它还要提供数据有效传输的端端(端到端)连接。在发送方,DLL需负责将指令、数据等包装到帧中,帧(frame)是DLL层生成的结构,它包含足够的信息,确保数据可以安全地通过本地局域网到达目的地。3.网络层网络层负责在源机器和目标机器之间建立它们所使用的路由。这一层本身没有任何错误检测和修正机制,因此,网络层必须依赖于端端之间的由DLL提供的可靠传输服务。4.传输层传输层提供类似于DLL所提供的服务,传输层的职责也是保证数据在端端之间完整传输,不过与DLL不同,传输层的功能是在本地LAN网段之上提供这种功能,它可以检测到路由器丢弃的包,然后自动产生一个重新传输请求。传输层的另一项重要功能就是将乱序收到的数据包重新排序,数据包乱序有很多原因。例如,这些包可能通过网络的路径不同,或者有些在传输过程中被破坏。不管是什么情况,传输层应该可以识别出最初的包顺序,并且在将这些包的内容传递给会话层之前要将它们恢复成发送时的顺序。5.会话层OSI会话层的功能主要是用于管理两个计算机系统连接间的通信流。通信流称为会话,它决定了通信是单工还是双工。它也保证了接受一个新请求一定在另一请求完成之后。6.表示层表示层负责管理数据编码方式,不是所有计算机系统都使用相同的数据编码方式,表示层的职责就是在可能不兼容的数据编码方式,例如在ASCII和EBCDIC之间,提供翻译。7.应用层OSI参考模型的最顶层是应用层,尽管它称为应用层,但它并不包含任何用户应用。相反,它只在那些应用和网络服务间提供接口。2.2TCP/IP参考模型与OSI参考模型不同,TCP/IP模型更侧重于互联设备间的数据传送,而不是严格的功能层次划分。它通过解释功能层次分布的重要性来做到这一点,但它仍为设计者具体实现协议留下很大的余地。因此,OSI参考模型在解释互联网络通信机制上比较适合,但TCP/IP成为了互联网络协议的市场标准。TCP/IP是处理上述所有操作并和远程主机通信的一个环境。TCP/IP由四层组成,这与OSI由七层组成不相同。这四层包括:1.链路层链路层包括ARP和RARP,负责报文传输。2.网络层网络层由以下协议组成:ICMP、IP、IGMP、RIP、OSPF和用于路由的EGP,用户不必操心这些,因为它们是相当底层的东西。3.传输层传输层包括UDP和TCP。UDP几乎不进行检查,而TCP提供传输保证。4.应用层应用层包括SMTP、FTP、NFS、NIS、LPD、Telnet和RemoteLogin。对于大多数Internet用户来说这些都是很熟悉的。以下章节我将详细介绍远程登录和文件传输功能的实现。第3章远程登录的功能实现3.1虚拟终端简单的说,远程登录让一台电脑连线载入另外一部电脑。在网络上的应用程序多半是采用Client/Server模式,也就是一定有一端是请求端,请求端执行远程登录请求程序。在主机这一端则有装置服务程序来接受连线请求,不过在多半的情况下,主机端则是Client与Server两者都有。远程登录的使用程序与您平常在本地通过电话线或任何其他方式载入一部主机并没有很大区别,您在对方主机一定要有一个私人使用帐号,以及您的通行密码,这样您才有办法连线进入该主机系统。另外,在Internet上,有相当多的各式各样服务系统也是通过这种方式来提供服务,其中绝大部分是免费的服务,像Hytelnet、BBS、Gopher及Archie等等就是,这类系统通常开放有公用帐号,且无须使用密码。远程登录协议是通过网络来调用服务器,并使自己的机器作为服务器的终端的协议。而作为远程登录协议安装的程序是远程登录客户端程序(参见图3.1)。虚拟终端通过网络连接到服务器远程登录客户端远程登录服务器可以利用网络功能自由选择服务器远程登录服务器图3.1虚拟终端远程登录客户端按图3.2所示连接到远程登录服务器,开始时,远程登录客户端对远程登录的标准端口23提出TCP连接请求。服务器建立其与客户端的TCP连接此后,客户端与服务器之间交换连接时所必需的信息。为了能成为虚拟终端,服务器和客户端双方必须确认客户端要采用的界面控制功能和服务器端所采用的终端控制功能,这种操作过程成为协商(negotiation)。协商的具体步骤由远程登录协议决定。协商结束之后,用户即可使用远程登录的终端功能了。此外,不仅是在会话开始,即使是在使用终端功能的过程中,如果有必要也要进行协商。从网络的观点来看,远程登录不过是一个只建立起远程登录的客户端与服务器之间的连接的简单协议,但要真正完成通信,远程登录客户端则需要一个结构相当复杂的程序。作为虚拟终端程序,远程登录必须提供终端功能。因此,除了完成协商以外,还要实现如画面控制和语言处理等终端仿真功能。此外,不同的服务器所提供的终端功能也会有差异,因此,对于每个希望连接的目的服务器的多样性,使的远程登录程序变得复杂起来。网络远程登录客户端远程登录服务器23号连接请求同意请求协商(negotiation)协商(negotiation)执行登录(login)接受登录(login)作为终端通信提供终端通信协商(必要时)协商(必要时)图3.2远程登录的连接过程3.2远程登录协议现在,让我们来浏览一下远程登录协议,也包括实际安装远程登录程序要重点注意的一些地方。根据RFC854,远程登录协议,依据由表3.1所示的3个中心思想构成。表3.1构成远程登录协议所遵循的3个中心思想1NVT(NetworkVirtualTerminal)具备最低限度的终端功能的网络虚拟终端。提供虚拟打印机和键盘。NVT提供基本的行方式的输入输出2协商的选项使用NVT以上的功能进行通信时,确定通过协商执行的选项3服务器端和客户端的对称性利用协商扩大通信功能,是服务器端和客户端的人以一方都可以对称的工作NVT(NetworkVirtualTerminal)定义了构成终端所应具备的最低限度的功能。使用远程登录协议尝试连接的初期,服务器端和客户端都要使用的NVT功能进行通信。远程登录协议中的协商可以从服务器端和客户端的任何一方执行,此即表4.1中所说的对称性。表3.2协商中使用的命令名称代码含义IAC255此后的数据作为命令解释(InterpretAsCommand)WLII(选项命令)251同意执行指定选项WONT(选项命令)252不同意执行指定选项DO(选项命令)253同意执行对方的指定选项的要求DONT(选项命令)254不同意执行对方的指定选项的要求SB250开始选项协商SE240结束选项协商协商通过以IAC为首的连续3个命令组合后进行。例如,使用RFC857中规定的回声选项(ECHO,代码为1)时,要向对方发送如下信息:IACWILLECHO(代码为2552552)开始的IAC表明接在它之后的数据都表示命令,第二和第三个字符串WILL和ECHO用于向对方说希望使用回声选项。对于WILL的回答可以是DO或DONT。例如,对于上例,如果同意使用回声选项,就应该使用DO返回如下形式的应答:IACDOECHO(代码为2552531)于是,双方之间达成了同意执行回声选项的协议。相反的,如果不同意执行回声选项,要使用DONT命令来应答:IACDON’TECHO(代码为2552541)上述讨论说明,对于利用WILL进行执行选项请求的应答总是DO或DON’T,这与使用WONT进行请求时的应答一样。想使对方执行选项时使用命令DO,而对应于DO的回答既可以是WILL,也可以是WONT。根据对称性,以上的协商可以从客户端和服务器端的任何一方执行,但通常是以从服务器端提出请求而客户端进行应答的方式进行协商。3.3有关远程登录的实现方法(线程的概念)仅通过简单地TCP连接设置是不能实现远程登录的。实际安装远程登录时,必须要考虑到如何进行协商和终端仿真等多种细致而繁复的工作。不过,如果不先建立连接,自然也就没有了后话也是事实。因此,我们先来设计能够实现从双向建立TCP连接的客户端程序。如果单说远程登录客户端程序的原型,或者说是工作在这一层次上的程序,他只要能够实现如图3.3所示的处理也就够了。在图3.3中,原始远程登录程序从TCP连接开始,TCP连接作为远程登录的输入并构成终端输出。之后,网络段应与来自标准输入端所形成的输入以及其他不同的输出端构成连接,及网络端应构成键盘输入和到其它网络输出的中介。远程登录客户端远程登录服务器图3.3远程登录原始程序的行为远程登录原始程序输出到屏幕从网络读入从键盘读入输出到网络网络利用指定服务器的地址和端口号开始TCP连接要经过一系列信息交换,如下所示:serversocket=newSocket(host,port);随后,可以对此socket进行读写操作,并可将结果送至标准输入输出。为此,必须构造负责输入输出的类中的OutputStream类以及BufferedInputStream类的对象,即进行如下的准备工作:ServerOutput=ServerSocket.getOutputStream();ServerInput=newBufferedInputStream(serversocket.getInputStream());利用上述对象进行读出和写入时,可以使用其read和write方法。先检查一下输入流的状态,只有在输入时进行处理。将上述方法稍微完善就得到了如图3.4所示的程序。while(true){byte[]buff=newbyte[1024];if(serverInput.available()>0){intn=serverInput.read(buff);system.out.write(buff,0,n);}if(System.in.available()>0){intn=System.in.read(buff)lserverOutput.write(buff,0,n);}}图3.4以网络和标准输入输出对应的两种读写操作图3.4中先使用available方法检查是否可以从输入流中读取数据,如果可以,则调用read方法将数据读入进来,再用标准数据将数据发送到服务器端。现在我们考虑使用线程(thread)的方法。线程是一种使程序可以并行执行的结构。如果是对象作为线程来执行,则不同的对象可以实现并行操作。那么,现将来自网络的输入和向网络的输出各自作为线程来处理,就可能实现输入和输出的并行操作了。作为使用现成的简单实例,此处给出了一个用于输出清单3.1中所示数据的程序Threadtest.java。Threadtest程序中利用2个线程来输出从2至10之间的数。由于线程执行的并行性,什么时候输出以及哪一个线程输出会因实际执行时的环境变化而改变。图3.5示出1和2两次实际运行的结果。尽管图中所示为相同环境,相同的操作系统以及同一个程序的实际运行结果,但线程的执行顺序也有差异。清单3.1线程的使用示例――Threadtest程序程序名Threadtest.Java处理内容概要执行2个输出从0到10递增的数值的线程结束条件2个线程结束时整个程序结束输入设备无输出设备显示器//线程测试程序Threadtest.Java//此程序输出从0到10的数,2个线程并行执行//使用方法:JavaThreadtest//导入库importjava.net.;importjava.io.;//Threadtest类//Threadtest类用于生成和管理线程publicclassThreadtest{//main方法publicstaticvoidmain(String[]arg){try{//生成线程是用的CountTen类的对象CountTenno1=newCountTen("No1");CountTenno2=newCountTen("No2");//生成线程Threadno1_thread=newThread(no1);Threadno2_thread=newThread(no2);//启动线程no1_thread.start();no2_thread.start();}catch(Exceptione){System.err.print(e);System.exit(1);}}}//CountTen类//从0至10递增的数classCountTenimplementsRunnable{Stringmyname;//构造器接受线程名publicCountTen(Stringname){myname=name;}//处理部分的函数体publicvoidrun(){inti;for(i=0;i<=10;++i){System.out.println(myname+":"+i);}}}在java语言中很同意将一个对象用作线程。作为对Runnable接口的实现,Threadtest程序中通过定义类来构造线程。就是说,应该按照如下形式来书写类名,进行类的定义,则类CountTen就可以作为线程来执行:classCountTenimplementsRunnable{……CountTen类的对象作为实际的线程启动时,类中的run方法就会被调用并执行相应地处理工作。CountTen的run方法的工作很简单,只是将0到10的数值一个一个地发送到标准输出上.图3.5Threadtest程序的运行实例在网络处理中,有很多是利用依赖线程进行并发处理的方法来描述的过程,简单易懂。如果也用如图3.6所示的2个线程来描述远程登录,则可以实现远程登录。远程登录客户端服务器(SMTP,HTTP)远程登录原始程序网络读取线程网络输出线程输出到屏幕从网络读入从键盘读入输出到网络网络服务器(SMTP,HTTP)图3.6利用线程实现远程登录3.4远程登录的最终完成远程登录是一个具有类似连接到HTTP服务器以读取数据,或是连接到SMTP服务器以发送邮件等功能的程序,并且考虑到了协商问题,因此可以真正成为远程登录客户端。通常,客户端要通知服务器端是否提供了VT-100等适当的终端仿真功能。为此远程登录客户端自然要用软件方法实现终端仿真功能。因此,所讨论的远程登录客户端程序也以支持最基本的协商和终端仿真功能为准。最基本的功能莫过于NVT。这里,我将实现以NVT为终端功能而进行的协商。图3.7给出了远程登录程序的启动方法和执行行为示例。程序清单由清单3.2给出。在图3.7中,利用远程登录程序连接到bbs.zsu.edu.cn(中山大学“逸仙时空”BBS)。图3.7远程登录程序的运行示例图3.7是一次执行远程登录的示例。根据连接方服务器的不同,上述过程和输出信息也有差异。此外,Ycdl.java程序在按下+C键时运行结束。即使与服务器的连接结束了,如果不按下+C键,Ycdl.java程序也不会自己终止。清单3.2远程登录程序程序名Ycdl.java处理内容概要建立连接,实现与指定地址的端口的标准输入输出操作。没有指定端口号是假定为23号端口若被连接方是23号端口时进行远程登录协商。结束条件按+C键结束输入输入设备键盘,网络输出设备显示器,网络//远程登录程序Ycdl.Java//此程序用于建立以实现与指定地址的端口进行标准输入输出操作的连接//若被连接方是远程登录端口(23号)时进行远程登录协商//协商时,拒绝服务器端的所有请求//使用方法(1):javaYcdl服务器地址端口号//使用方法(2):javaYcdl服务器地址(2)的场合,假定端口号为23号(远程登录端口)//运行示例:javaYcdlbbs.zsu.edu.cn//要结束请按+C键//导入库importjava.net.;importjava.io.;//Ycdl类//Ycdl类用于实现网络连接管理//利用StreamConnector类进行线程处理//有2种构造器,分别对应使用方法(1)和(2)publicclassYcdl{SocketserverSocket;//连接用SocketpublicOutputStreamserverOutput;//用于网络输出的流publicBufferedInputStreamserverInput;//用于网络输入的流Stringhost;//连接服务器地址intport;//连接服务器的端口号staticfinalintDEFAULT_YCDL_PORT=23;//远程登录的端口号(23号)//构造器(1):指定地址和端口号时用publicYcdl(Stringhost,intport){this.host=host;this.port=port;}//构造器(2)只指定地址时用publicYcdl(Stringhost){this(host,DEFAULT_YCDL_PORT);//假定为远程登录端口}//openConnection方法//有地址和端口号构成Socket而形成流publicvoidopenConnection()throwsIOException,UnknownHostException{serverSocket=newSocket(host,port);serverOutput=serverSocket.getOutputStream();serverInput=newBufferedInputStream(serverSocket.getInputStream());//若连接的是远程登录端口则进行协商if(port==DEFAULT_YCDL_PORT){negotiation(serverInput,serverOutput);}}//main_proc方法//启动进行网络处理的线程publicvoidmain_proc()throwsIOException{try{//生成线程用StreamConnector类的对象StreamConnectorstdin_to_socket=newStreamConnector(System.in,serverOutput);StreamConnectorsocket_to_stdout=newStreamConnector(serverInput,System.out);//生成线程Threadinput_thread=newThread(stdin_to_socket);Threadoutput_thread=newThread(socket_to_stdout);//启动线程input_thread.start();output_thread.start();}catch(Exceptione){System.err.print(e);System.exit(1);}}//定义用于协商的命令staticfinalbyteIAC=(byte)255;staticfinalbyteDONT=(byte)254;staticfinalbyteDO=(byte)253;staticfinalbyteWONT=(byte)252;staticfinalbyteWILL=(byte)251;//negotiation方法//利用NVT进行协商通信staticvoidnegotiation(BufferedInputStreamin,OutputStreamout)throwsIOException{byte[]buff=newbyte[3];//接受命令的数组while(true){in.mark(buff.length);if(in.available()>=buff.length){in.read(buff);if(buff[0]!=IAC){//协商结束in.reset();return;}elseif(buff[1]==DO){//对于DO命令……buff[1]=WONT;//用WON\'T作为应答out.write(buff);}}}}//main方法//建立TCP连接,开始处理publicstaticvoidmain(String[]arg){try{Ycdlt=null;//有参数个数决定调用哪个服务器switch(arg.length){case1://只指定服务器地址t=newYcdl(arg[0]);break;case2://指定地址和端口t=newYcdl(arg[0],Integer.parseInt(arg[1]));break;default://使用方法不正确时System.out.println("usage:javaYcdl{}");return;}t.openConnection();t.main_proc();}catch(Exceptione){e.printStackTrace();System.exit(1);}}}//StreamConnector类//接受流参数以二者结合实现数据传递//StreamConnector类是用于构造线程的类classStreamConnectorimplementsRunnable{InputStreamsrc=null;OutputStreamdist=null;//构造器接受输入输出流publicStreamConnector(InputStreamin,OutputStreamout){src=in;dist=out;}//执行处理的函数体//无限循环进行流的读写publicvoidrun(){byte[]buff=newbyte[1024];while(true){try{intn=src.read(buff);if(n>0)dist.write(buff,0,n);}catch(Exceptione){e.printStackTrace();System.err.print(e);System.exit(1);}}}}下面,我们来解释一下远程登录程序中的重点内容。远程登录程序中定义了两个类,其一是作为线程模板的StreamConnector类,其二是用于实现网络连接管理的远程登录类。关于StreamConnector类的工作处理,2个流用以实现二者之间的数据交互。构造器StreamConnector的接受2个流对象,分别高背给自己内部的InputStream类对象src成员和OutputStream类对象成员dist。实现处理的函数体很简单,将从对象src用read方法读出的数据存储在byte类型的数组buff中,按数据的个数使用dist的write方法将数据全部读入此对象,此过程无限循环。此外远程登录类中包含4个方法和两个构造器。根据执行命令是否携带端口号而有2种参数处理方法,分别对应着不同的构造函数。如果没有指定端口号,则使用远程登录协议的缺省端口号23与服务器建立连接。4个方法中除了mian方法外,还有用于建立TCP连接并进行处理的方法openConnection,用于生成并启动线程的main_proc方法,和用于协商的negotiation方法。Main方法负责生成远程登录类的一个对象t,使用t实现后续操作。Ycdlt=null;首先由参数个数来判断调用哪个构造器switch(arg.length){case1://只指定服务器地址t=newYcdl(arg[0]);break;case2://指定地址和端口t=newYcdl(arg[0],Integer.parseInt(arg[1]));break;default://使用方法不正确时System.out.println("usage:javaYcdl{}");return;}然后再调用openConnection方法建立连接。OpenConnection方法要求使用被连接的目标计算机名和端口号作为参数。t.openConnection();若连接成功,接着将构造线程。为此,须调用main_proc方法。t.main_proc();执行完上述代码后,main方法的处理工作也就结束了。程序中的catch以后的剩余部分用于异常处理。由main第一个调用方法openConnection根据传递来的参数,即地址和端口号构成socket(套接字),从而形成输入输出流。由地址和端口构成socket并藉此进行输入输出的所谓网络存取的结构都与前述的操作方法相同。Main_proc方法按与前述的含有线程的Threadtest示例程序同样的方法构造线程。生成线程后,利用标准输入输出和用于网络交互的流进行组合,形成清单3.2所示的程序。下面我来详细介绍一下negotiation方法,它主要负责协商的工作。这里,由于只使用NVT功能进行通信,故须拒绝服务器端的所有有关执行选项的请求。就是说,对于WILL的请求权不用DON’T作为应答。Negotiation方法的中心内容如图所示3.8所示。协商处理过程进行到从服务器端不再接收到IAC命令时结束。处理开始时,使用mark方法将协商开始时从网路上读取的位置记录下来。协商过程结束时,利用reset方法重新开始自mark的位置起始的服务器-客户端之间的通信。图3.8中的elseif部分是返回给服务器的应答。尽管远程登录协议中使用有3个码组合成的命令进行协商处理,但此处的第二个码是DO时,都将其换成WONT作为应答返回给服务器。while(true){in.mark(buff.length);if(in.available()>=buff.length){in.read(buff);结束协商的处理方法协商处理的往受理要求返和处理}}图3.8协商处理的中心内容这样一来,无论服务器端提出什么样的请求,都将被拒绝。由此可见,远程登录程序可以利用最低限度的功能实现与服务器连接。远程登录程序的流程图由图3.9给出。Main方法由参数个数决定调用哪个构造器生成Ycdl类的对象topenconnection方法if(端口号=23)noyes进行协商main_proc方法生成线程,启动线程,出错处理,调用StreamConnector构造器run方法if(buff[0]!=IAC){//协商结束in.reset();return;}elseif(buff[1]==DO){//对于DO命令…buff[1]=WONT;//用WON\'T作为应答out.write(buff);}}对DO命令的WONT应答建立TCP连接启动进行网络处的线程读出输入流数据存入buff中,再发送到服务器图3.9远程登录流程图第4章文件传输的执行行为和功能4.1传输文件文件传输是与远程登录一样在因特网上广为应用的协议之一。文件传输是Internet上最早出现的服务功能之一,但是到目前为止,它仍然是Internet上最常用也是最重要的服务之一。文件传输的主要作用,就是让用户连接上一个远程计算机(这些计算机上运行着文件传输服务器程序,并且储存有成千上万个非常有用的文件,包括计算机软件、声音文件、图像文件、重要资料、电影……),查看远程计算机有哪些文件,然后把这些文件从远程计算机上复制到本地计算机,或把本地计算机的文件送到远程计算机上。在2台装有相同操作系统的计算机之间,可以很容易地实现文件的共享。但是,不同的系统如UNIX和Windows之间,要实现文件的共享就要费一番周折。此时,或者在2台计算机之间增设文件传输结构,或者利用网络媒介作为交换文件的手段,总之,都需要使用文件传输协议。应该说,文件传输解决了在不同计算机上工作的操作系统之间的差异问题,可以实现通用的文件传输。Windows中附带的文件传输客户端程序中所支持的命令示于表4.1中。表4.1Windows附带的文件传输客户端程序中支持的命令示例无限循环进行流的读写命令名说明!临时转换外壳?显示帮助ascii选择文本传输模式binary选择二进制传输模式bye关闭连接并结束文件传输命令cd目录切换close关闭连接dir显示服务器端的目录清单get读取服务器端的文件lcd客户端目录切换ls显示服务器端文件清单(简单形式)mget读取服务器的多个文件mput从客户端向文件服务器发送多个文件open服务器连接设置put从客户端向文件服务器发送文件quit关闭连接并结束文件传输命令(与bye相同)user服务器端的用户设置4.2文件传输的传输模式利用文件传输进行文件传输时,客户端和服务器端与远程登录的结构非常相似,但实际上,文件传输的传输模式与远程登录还是有一些差别的.应该说,使用远程登录也可以连接到服务器的文件传输端口,但不能正确地实现文件传输,原因是文件传输与远程登录及HTTP等协议不同,采用2个独立的通道完成会话。图4.1所示为文件传输中数据传输模式示意图。正如图中所示的那样,文件传输协议的一个会话共有2个单独的会话组成,其一是用于控制的TCP连接,其二则是传输文件等数据的TCP连接。控制用端口号连接21传输数据连接20文件传输客户端文件传输服务器图4.1文件传输的传输模式要进行文件传输会话,首先要使用负责传输控制的TCP连接客户端和服务器之间的会话。此时,文件传输服务器端的端口号是21(参见图4.1)。此后,当有文件传输等请求时,就会在客户端准备好用于建立从服务器到此客户端的数据传输连接用的socket。可见,这种情况下,服务器socket是由文件传输客户端来构造的。原因是此时服务器端所准备的端口号是任意的,如果不通知服务器端就不能实现从服务器到客户端的连接。这里,客户端准备好端口号,然后再利用控制会话将此端口号通知给服务器。在文件传输会话过程中,利用控制会话将客户端的命令传送给服务器,再将服务器的处理结果返回给客户端,这种循环称为cycle。从客户端发出的命令于表4.1所示的特定的客户的命令不同,是由文件传输协议确定的命令。对于表4.1中所示的命令,服务器端要先对命令进行解释,然后再进行适当的处理。此时,服务器端要利用控制会话对客户端进行应答,应答由3位代码后接信息组成,表4.3给出了应答代码的示例。表4.3文件传输的应答代码示例第一位的值代码含义1(准备阶段的肯定应答)125传输数据连接已经就绪150文件状态正常2(完成时的肯定应答)200命令正确202命令没有实际执行220端口用尽,不能连接新用户226传输数据连接结束230用户正在登录250请求的文件处理结束3(中间的肯定应答)331用户名正确,需要口令4(暂时的否定应答)421控制连接关闭425传输数据连接未建立426连接关闭,传输过程被中断450没执行请求的文件处理5(永久的否定应答)500语法错误501参数的语法错误502命令未执行530未登录在图4.2中,首先看到是向文件传输服务器登陆的过程。对此,文件传输服务器利用以应答码230开始的信息报告登录成功。随之,文件传输客户端软件使用ls命令显示目录清单。图4.2文件传输会话开始及使用LIST命令取得目录信息文件传输有称为A和I的2种模式.处理文本数据时应使用A(ascii)模式,而处理二进制数据时应使用binary命令切换到I(image)模式。图4.3指定选用的模式为A传输文件。4.3图传输示例4.3构造控制连接和数据连接要实现最简单的文件传输也就是要在客户端计算机上准备好控制连接和传输数据连接即可。选择序号1的作用是如图4.4所示的向服务器注册。再次运行示例中,来自服务器的信息可能因连接方服务器的种类不同而有差异。Wjcs2.java的源代码由清单4.1给出。清单4.1Wjcs2程序//文件传输程序Wjcs2.java//此程序的功能是建立文件传输服务器的连接//准备数据连接,执行LIST命令//没有文件传输功能//使用方法:javaWjcs2服务器地址程序名Wjcs2.java处理内容概要与文件传输服务器建立控制连接,在建立数据连接并执行LIST命令结束条件输入quit命令结束输入设备键盘,网络输出设备显示器,网络//启动示例javaWjcs2202.102.2.218//导入库importjava.net.;importjava.io.;//Wjcs2类publicclassWjcs2{//socket准备SocketctrlSocket;//控制用socketpublicPrintWriterctrlOutput;//控制输出用的流publicBufferedReaderctrlInput;//控制输入用的流finalintCTRLPORT=21;//文件传输控制用的端口//openConnection方法//由地址和端口号构成socket形成控制用的流publicvoidopenConnection(Stringhost)throwsIOException,UnknownHostException{ctrlSocket=newSocket(host,CTRLPORT);ctrlOutput=newPrintWriter(ctrlSocket.getOutputStream());ctrlInput=newBufferedReader(newInputStreamReader(ctrlSocket.getInputStream()));}//closeConnection方法//关闭控制用的socketpublicvoidcloseConnection()throwsIOException{ctrlSocket.close();}//showMenu方法//输出文件传输的命令菜单publicvoidshowMenu(){System.out.println(">Command?");System.out.print("1login");System.out.print("2ls");System.out.print("3cd");System.out.println("9quit");}//getCommand方法//读取用户指定的命令序号publicStringgetCommand(){Stringbuf="";BufferedReaderlineread=newBufferedReader(newInputStreamReader(System.in));while(buf.length()!=1){//循环接收一个字符的输入try{buf=lineread.readLine();}catch(Exceptione){e.printStackTrace();System.exit(1);}}return(buf);}//doLogin方法//登录到文件传输服务器publicvoiddoLogin(){StringloginName="";Stringpassword="";BufferedReaderlineread=newBufferedReader(newInputStreamReader(System.in));try{System.out.println("请输入用户名");loginName=lineread.readLine();//利用USER命令登录ctrlOutput.println("USER"+loginName);ctrlOutput.flush();//利用PASS命令输入口令System.out.println("请输入口令");password=lineread.readLine();ctrlOutput.println("PASS"+password);ctrlOutput.flush();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doQuit方法//从文件传输服务器注销publicvoiddoQuit(){try{ctrlOutput.println("QUIT");//发送QUIT命令ctrlOutput.flush();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doCd方法//切换目录publicvoiddoCd(){StringdirName="";BufferedReaderlineread=newBufferedReader(newInputStreamReader(System.in));try{System.out.println("请输入目录名");dirName=lineread.readLine();ctrlOutput.println("CWD"+dirName);//CWD命令ctrlOutput.flush();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doLs方法//取得目录信息publicvoiddoLs(){try{intn;byte[]buff=newbyte[1024];//建立数据连接SocketdataSocket=dataConnection("LIST");//准备读取数据用的流BufferedInputStreamdataInput=newBufferedInputStream(dataSocket.getInputStream());//读取目录信息while((n=dataInput.read(buff))>0){System.out.write(buff,0,n);}dataSocket.close();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//dataConnection方法//构造与服务器交换数据用的socket//再用port命令将端口通知服务器publicSocketdataConnection(Stringctrlcmd){Stringcmd="PORT";//PORT存放用PORT命令传递数据的变量inti;SocketdataSocket=null;//传送数据用sockettry{//得到自己的地址byte[]address=InetAddress.getLocalHost().getAddress();//用适当的端口号构造服务器ServerSocketserverDataSocket=newServerSocket(0,1);//准备传送PORT命令用的数据for(i=0;i<4;++i)cmd=cmd+(address[i]&0xff)+",";cmd=cmd+(((serverDataSocket.getLocalPort())/256)&0xff)+","+(serverDataSocket.getLocalPort()&0xff);//利用控制用的流传送PORT命令ctrlOutput.println(cmd);ctrlOutput.flush();//向服务器发送处理对象命令(LIST,RETR,及STOR)ctrlOutput.println(ctrlcmd);ctrlOutput.flush();//接受与服务器的连接dataSocket=serverDataSocket.accept();serverDataSocket.close();}catch(Exceptione){e.printStackTrace();System.exit(1);}returndataSocket;}//execCommand方法//对应各种命令分别调用其处理方法publicbooleanexecCommand(Stringcommand){booleancont=true;switch(Integer.parseInt(command)){case1://login处理doLogin();break;case2://显示服务器的目录信息doLs();break;case3://切换服务器的工作目录doCd();break;case9://处理结束doQuit();cont=false;break;default://其他输入System.out.println("请输入一个序号");}return(cont);}//main_proc方法//输出文件传输命令菜单,调用各种处理方法publicvoidmain_proc()throwsIOException{booleancont=true;try{while(cont){//输出菜单showMenu();//接受命令并执行cont=execCommand(getCommand());}}catch(Exceptione){System.err.print(e);System.exit(1);}}//getMsgs方法//启动从控制流收信的线程publicvoidgetMsgs(){try{CtrlListenlistener=newCtrlListen(ctrlInput);Threadlistenerthread=newThread(listener);listenerthread.start();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//main方法//建立TCP连接,开始处理publicstaticvoidmain(String[]arg){try{Wjcs2f=null;f=newWjcs2();f.openConnection(arg[0]);//建立控制连接f.getMsgs();//启动收信线程f.main_proc();//文件传输处理f.closeConnection();//关闭连接System.exit(0);//程序结束}catch(Exceptione){e.printStackTrace();System.exit(1);}}}//CtrlListen类classCtrlListenimplementsRunnable{BufferedReaderctrlInput=null;//构造器指定读取地址publicCtrlListen(BufferedReaderin){ctrlInput=in;}publicvoidrun(){while(true){try{//按行读入并输出到标准输出上System.out.println(ctrlInput.readLine());}catch(Exceptione){System.exit(1);}}}}Wjcs2程序中利用Wjcs2类的main方法执行如下的处理:f.openConnection(arg[0]);//控制连接的设置f.getMsgs();//启动接收线程f.main_proc();//文件传输处理f.closeConnection();//关闭连接openConnection方法负责建立与文件传输服务器的控制连接,服务器的地址由参数指定。getMsgs()方法利用CtrlListen类接受来自控制连接的信号,创建收信线程。Main_proc方法负责从控制连接收信以外的事情,即负责显示客户端的命令菜单和接收用户输入的命令,进而调用执行与命令相应的处理方法,继续执行文件传输处理。Main方法中最后调用的closeconnection方法用于关闭控制连接。作为处理中心的main_proc方法中的主要代码如下:while(cont){//输出菜单showMenu();//接受命令并执行cont=execCommand(getConmmand());}showMenu方法的功能是将菜单在标准输出设备上显示出来。GetConmmand方法接收用户输入的一个字符,并以此作为返回值并指向对应的处理功能。各种情况的处理有下述switch语句实现:switch(Integer.parseInt(command)){case1://login处理doLogin();break;case9://处理结束doQuit();cont=false;break;default://除此以外的输入System.out.println("请选择一个序号");}DoLogin方法执行向文件传输服务器的登录。具体的说,就是要求用户输入用户名和口令,并使用控制连接发送给文件传输服务器。DoQuit方法极为简单,只负责向文件传输服务器发送QUIT命令,这里,再发送完命令之后仍要调用flush方法清空缓冲区。ctrlOutput.println("QUIT");//发送QUIT命令ctrlOutput.flush();图4.4为能够取得目录信息之类的目的Wjcs2程序的运行示例。由图可见,Wjcs2程序可以执行数据连接所需的LIST命令。图4.4Wjcs2程序的运行示例其中,在doLs方法中要使用dataConnection方法建立与文件传输服务器之间的数据连接。初始时,要构造建立数据连接用的socket,由此构成对应的流://建立数据连接SocketdataSocket=dataConnection("LIST");//准备读取数据用的流BufferedInputStreamdataInput=newBufferedInputStream(dataSocket.getInputStream());随后,利用已构造好的流从数据连接读取数据,再写到标准输出上。当从连接上读取数据完毕后,就将连接关闭。//读取目录信息while((n=dataInput.read(buff))>0){System.out.write(buff,0,n);}dataSocket.close();4.4文件传输程序的完成应该说,Wjcs2程序已经可以实现文件传输客户端的最基本功能了,此处在给出经过最后扩充的文件传输完成程序。对于文件传输程序,在文件传输对话开始时必须要进行注册,并成为能够指定传输模式那样。图4.2是文件传输程序运行示例,其程序源代码由清单4.3给出。清单4.3Wjcs程序//文件传输程序Wjcs.java//此程序的功能是建立与文件传输服务器的连接并实现文件传输//使用方法:javaWjcs服务器地址//运行示例:javaWjcs202.102.2.218//导入库程序名Wjcs.java处理内容概要与文件传输服务器建立控制连接,在执行文件传输结束条件输入quit命令结束输入设备键盘,网络以及文件输出设备显示器,网络以及文件importjava.net.;importjava.io.;//Wjcs类publicclassWjcs{//准备socketSocketctrlSocket;//控制用socketpublicPrintWriterctrlOutput;//控制输出用的流publicBufferedReaderctrlInput;//控制输入用的流finalintCTRLPORT=21;//文件传输的控制用端口//openConnection方法//由地址和端口,构造socket形成控制用的流publicvoidopenConnection(Stringhost)throwsIOException,UnknownHostException{ctrlSocket=newSocket(host,CTRLPORT);ctrlOutput=newPrintWriter(ctrlSocket.getOutputStream());ctrlInput=newBufferedReader(newInputStreamReader(ctrlSocket.getInputStream()));}//closeConnection方法//关闭控制用的socketpublicvoidcloseConnection()throwsIOException{ctrlSocket.close();}//showMenu方法//输出文件传输的命令菜单publicvoidshowMenu(){System.out.println(">Command?");System.out.print("2ls");System.out.print("3cd");System.out.print("4get");System.out.print("5put");System.out.print("6ascii");System.out.print("7binary");System.out.println("9quit");}//getCommand方法//读取用户指定的命令符号publicStringgetCommand(){Stringbuf="";BufferedReaderlineread=newBufferedReader(newInputStreamReader(System.in));while(buf.length()!=1){//循环接收一个字符的输入try{buf=lineread.readLine();}catch(Exceptione){e.printStackTrace();System.exit(1);}}return(buf);}//doLogin方法//登录文件传输服务器publicvoiddoLogin(){StringloginName="";Stringpassword="";BufferedReaderlineread=newBufferedReader(newInputStreamReader(System.in));try{System.out.println("请输入用户名");loginName=lineread.readLine();//用USER命令登录ctrlOutput.println("USER"+loginName);ctrlOutput.flush();//用PASS命令输入口令System.out.println("请输入口令");password=lineread.readLine();ctrlOutput.println("PASS"+password);ctrlOutput.flush();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doQuit方法//向文件传输服务器注销publicvoiddoQuit(){try{ctrlOutput.println("QUIT");//QUIT发送QUIT命令ctrlOutput.flush();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doCd方法//切换目录publicvoiddoCd(){StringdirName="";BufferedReaderlineread=newBufferedReader(newInputStreamReader(System.in));try{System.out.println("请输入目录名");dirName=lineread.readLine();ctrlOutput.println("CWD"+dirName);//CWD命令ctrlOutput.flush();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doLs方法//取得目录信息publicvoiddoLs(){try{intn;byte[]buff=newbyte[1024];//建立数据连接SocketdataSocket=dataConnection("LIST");//准备读取数据用的流BufferedInputStreamdataInput=newBufferedInputStream(dataSocket.getInputStream());//读取目录信息while((n=dataInput.read(buff))>0){System.out.write(buff,0,n);}dataSocket.close();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//dataConnection方法//构造与服务器交换数据用的socket//再用PORT命令将端口号通知给服务器publicSocketdataConnection(Stringctrlcmd){Stringcmd="PORT";//PORT存储用PORT命令传输的数据用的变量inti;SocketdataSocket=null;//传送数据用sockettry{//取得自己的地址byte[]address=InetAddress.getLocalHost().getAddress();//用适当的端口号构造服务器socketServerSocketserverDataSocket=newServerSocket(0,1);//准备传送PORT命令用的数据for(i=0;i<4;++i)cmd=cmd+(address[i]&0xff)+",";cmd=cmd+(((serverDataSocket.getLocalPort())/256)&0xff)+","+(serverDataSocket.getLocalPort()&0xff);//利用控制用的流发送PORT命令ctrlOutput.println(cmd);ctrlOutput.flush();//向服务器发送处理对象命令(LIST,RETR及STOR)ctrlOutput.println(ctrlcmd);ctrlOutput.flush();//受理服务器的连接dataSocket=serverDataSocket.accept();serverDataSocket.close();}catch(Exceptione){e.printStackTrace();System.exit(1);}returndataSocket;}//doAscii方法//设置文本传输模式publicvoiddoAscii(){try{ctrlOutput.println("TYPEA");//A模式ctrlOutput.flush();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doBinary方法//设置二进制传输模式publicvoiddoBinary(){try{ctrlOutput.println("TYPEI");//I模式ctrlOutput.flush();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doGet方法//取得服务器上的文件publicvoiddoGet(){StringfileName="";BufferedReaderlineread=newBufferedReader(newInputStreamReader(System.in));try{intn;byte[]buff=newbyte[1024];//指定服务器上的文件的名称System.out.println("请输入文件名");fileName=lineread.readLine();//在客户端上准备存储器内容的文件FileOutputStreamoutfile=newFileOutputStream(fileName);//构造传输文件用的数据流SocketdataSocket=dataConnection("RETR"+fileName);BufferedInputStreamdataInput=newBufferedInputStream(dataSocket.getInputStream());//从服务器上读取数据并存储到文件中while((n=dataInput.read(buff))>0){outfile.write(buff,0,n);}dataSocket.close();outfile.close();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//doPut方法//向服务器发送文件publicvoiddoPut(){StringfileName="";BufferedReaderlineread=newBufferedReader(newInputStreamReader(System.in));try{intn;byte[]buff=newbyte[1024];FileInputStreamsendfile=null;//指定文件名System.out.println("请输入文件名");fileName=lineread.readLine();//准备读出客户端的文件try{sendfile=newFileInputStream(fileName);}catch(Exceptione){System.out.println("文件不存在");return;}//准备发送数据的流SocketdataSocket=dataConnection("STOR"+fileName);OutputStreamoutstr=dataSocket.getOutputStream();//读出文件,经由网络发送给服务器while((n=sendfile.read(buff))>0){outstr.write(buff,0,n);}dataSocket.close();sendfile.close();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//execCommand方法//调用与命令对应的各种处理方法publicbooleanexecCommand(Stringcommand){booleancont=true;switch(Integer.parseInt(command)){case2://显示服务器上的目录信息doLs();break;case3://切换服务器的工作目录doCd();break;case4://从服务器取得文件doGet();break;case5://向服务器发送文件doPut();break;case6://文件传输模式doAscii();break;case7://二进制传输模式doBinary();break;case9://处理结束doQuit();cont=false;break;default://其他的输入System.out.println("请选择一个序号");}return(cont);}//main_proc方法//输出文件传输的命令菜单并进行各种处理publicvoidmain_proc()throwsIOException{booleancont=true;try{//进行登录doLogin();while(cont){//输出菜单showMenu();//接受并执行命令cont=execCommand(getCommand());}}catch(Exceptione){System.err.print(e);System.exit(1);}}//getMsgs方法//启动接收控制流的线程publicvoidgetMsgs(){try{CtrlListenlistener=newCtrlListen(ctrlInput);Threadlistenerthread=newThread(listener);listenerthread.start();}catch(Exceptione){e.printStackTrace();System.exit(1);}}//main方法//建立TCP连接,开始处理publicstaticvoidmain(String[]arg){try{Wjcsf=null;if(arg.length<1){System.out.println("usage:javaWjcs");return;}f=newWjcs();f.openConnection(arg[0]);//建立控制连接f.getMsgs();//启动接收线程f.main_proc();//文件传输处理f.closeConnection();//关闭连接System.exit(0);//结束程序}catch(Exceptione){e.printStackTrace();System.exit(1);}}}//CtrlListen类classCtrlListenimplementsRunnable{BufferedReaderctrlInput=null;//构造器指定读取地点publicCtrlListen(BufferedReaderin){ctrlInput=in;}publicvoidrun(){while(true){try{//按行读入并写到标准输出上System.out.println(ctrlInput.readLine());}catch(Exceptione){System.exit(1);}}}}Wjcs程序与Wjcs2程序有如下一些差异:\uf06c对showMenu菜单有所更改,在其中删除了序号1(login),增加了序号4(get)和5(put)\uf06c对exeCommand命令有所更改,在swith结构中删除了1(login),增加了对4(get)和5(put)的处理\uf06c增加了doput方法,并禁止指定不存在的文件\uf06c增加了doGet方法\uf06c增加了dataConnection方法\uf06c增加了doAscii方法\uf06c增加了doBinary方法在Wjcs程序中,login不包含在菜单中,使用户在开始会话时必须进行登录。此外,增加了doAscii方法和doBinary方法,使程序可以进行传输模式切换。Wjcs程序流程图4.7给出。Main方法进入main主函数,为实现调用其它函数作准备openConnection方法以host为参数构造ctrlOutput和ctrlIutput流getmsgs方法生成Wjcs类对象f由地址和端口,构造socket形成控制用的流调用ctrllisten类,创建收信线程run()函数调用此函数,接受服务器的信息main_proc方法先进行登录,再调用showmenu()方法,输出菜单showmenu()方法输出菜单execcommand方法LsCdGetPutdoAsciidoBinarydoQuit其他输入调用doLs方法取得目录信息调用doput方法向服务器发送文件调用dobinary方法设置二进制dataconnection方法传输模式构造socket,实现调用doget方法与服务器交换数据取得服务器上的文件调用doquit方法向文件传输服务器调用doCd方法调用doascii方法注销切换目录设置文本传输模式调用closeconnection方法关闭控制用的socket启动接收控制流的线程用的流读取一组数据,即写到标准输出输出文件传输的命令菜单并进行各种处理输出文件传输的命令菜单调用与命令对应的各种处理方法图4.7WJCS程序流程图结束程序第5章总结在做毕业设计以前,我对文件传输和远程登录的理解只是停留在理论知识的水平上,是“纸上谈兵”,缺乏实际的程序开发经验。这次通过做毕业设计,我们基本完成了谭老师下达的开发任务。在整个开发过程中遇到了很多问题,现对其中比较主要的几点体会总结如下:其一,我感到非常头疼的是对具体的功能实现的不了解。经过谭老师不厌其烦的启发和引导后,终于完成了程序的分析和设计工作。其二,本程序是要求用java进行开发。而我主攻的是c和asp,因此在接到任务后的一两个星期我潜心研究java的语法,和编程技巧,然后再边开发边学习,其中遇见了很多问题,但都能一一解决,当然这与指导老师的莫大帮助是分不开的。其三,从教条主义到理论联系实际的转变。因为我没有写毕业论文的经验,所以开始总是生搬硬套书本上的理论和概念,结果写出来的论文就非常的死板,缺乏新意,不能真正描述出自己程序的开发过程,犯了教条主义的错误。后来经过老师的指点,就对论文从结构和内容上都进行了大幅度的调整和修改,删除了论文中过多的理论和概念,利用理论知识把自己实际的开发过程,用自己的语言和科学方法清楚地表达出来,经过多次修改最终完成了论文的写作。这使我们体会到了什么叫理论联系实际。总之,经过这几个月的努力,我最终完成了“基于java的文件传输和远程登录功能实现”的开发。在整个开发过程中,我不仅学会了java,体验了开发的苦与乐,而且也达到了锻炼自己的目的,同时进一步加深了对编程的认识和理解。参考文献[1]熊桂喜,王小虎.计算机网络[M].清华大学出版社2002[2]宋波,董小梅.java应用设计[M].人民邮电出版社2001[3]飞思科技产品研发中心.javaTCP/IP.应用开发详解[M]电子工业出版社2002[4]金勇华,曲俊生.java网络高级编程.人民邮电出版社2001[5]张曜,张青,郭立山.Java程序设计教程.冶金工业出版社2002[6]TimParkerMarkSportack.TCP/IP技术大全.机械工业出版社2001[7]殷兆麟,付慧生,赵纪平..Java网络编程基础.清华大学出版社2004谢辞历经几个月奋斗,本次毕业设计基本圆满完成。在这三个多月中,得到不少老师和同学的大力帮助和不吝赐教,在这里首先感谢指导老师—谭敏生,感谢他为我的设计所做的辛苦工作,另外感谢四年来所有教导过我的老师,没有他们以前的辛苦教诲,则不可能有今天的顺利设计,再者,还要感谢我的一些同学在设计中给我提出的大量的宝贵意见。光阴似箭,大学四年匆匆之间就要结束了,回首大学四年学习和生活,老师们的关心与教导,传授我们丰厚的科学文化知识,以及做人的道理等。同学之间和睦相处,兄弟姐妹般的情感,将成为我们走上社会的宝贵财富。再一次深深地感谢各位领导、老师、同学深深地祝福你们!衷心的感谢所有支持帮助我的人们!',)


  • 编号:1700774462
  • 分类:其他文档
  • 软件: wps,office word
  • 大小:55页
  • 格式:docx
  • 风格:商务
  • PPT页数:5115392 KB
  • 标签:

广告位推荐

相关其他文档更多>