资源描述
,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,29,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,33,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,22,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,21,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,15,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,28,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,18,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,23,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,71,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,40,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,80,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,17,页,第,#,页,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,共,19,页,第,1,页,第,1,章,网络程序设计,第,2,页,主要内容,选择,JAVA,语言,网络常识,网络程序设计简介,网络程序设计技术,Java,支持的网络程序设计,移动网络,Java,安全性常识,本章小结,实践检验,第,3,页,1-1,选择,JAVA,语言,互联网在世界上蓬勃发展,,Sun,公司发现,Oak,语言所具有的跨平台、面向对象、安全性高等特点非常符合互联网的需要,于是改进了该语言的设计,造就了一代成功的编程语言。,第,4,页,1-2,网络常识,网络体系结构,协议,OSI,参考模型,命名与路由,Internet,地址,第,5,页,1-2-1,网络体系结构,网络中的设备既可以在同一个房间内,又可以分布于整幢大楼。或者通过电话线、微波等类似设备,分布于更远的距离。通过使用一些远距离介质,网络甚至可以分布于整个世界。,第,6,页,1-2-2,协议,“,协议”通常是指两个或更多的计算机之间,为交换信息所必须遵循的一组规则。它描述了计算机发送信息所应具有的格式,以及对收到的信息应作出何种响应。正是有了协议的存在,使得开发人员能够使用不同的程序设计语言,以不同的数据结构和命令代码,独立地开发和实现分布式应用程序的不同部分。,第,7,页,1-2-3 OSI,参考模型,OSI,协议层,第,8,页,1-2-3 OSI,参考模型,应用层 这一层负责发送数据给用户。它主要定义了一个到服务的接口。此层协议有:文件传输协议(,FTP,)、远程登录(,Telnet,)和简单邮件传输协议(,SMTP,)。,表示层 实现此层的协议负责在网络的表示层传输数据,它独立于底层的平台。如果要进行加密,将在此层完成。此层的协议有:,XDR,和,ASN.1,。,会话层 此层负责在两个进程间建立通信,以及进行错误恢复。需要注意的是,在无连接通信时,不需要此层。,传输层 在这一层,信息被编址到通信端口。此层既可以用于无连接的情况(如,UDP,),又可以用于面向连接的情况(,TCP,),这一点将在第,2,章进一步介绍。,网络层 两台计算机将在此层进行数据包的传递。这一层也负责进行路由(广域网中如此,局域网中不需路由)。此层协议有:,IP,和,X.25,。,数据链路层 此层负责两台计算机间包的容错传输。,物理层 此层包括驱动网络的线路及硬件等。,第,9,页,1-2-4,命名与路由,当一台主机要向,/,从处于同一个网络或不同网络中的另一台主机发送,/,接收包时就要用到,IP,地址。如果该主机向处于同一个网络中的主机发送包,那么只要用主机标识符来定位即可;如果该主机向处于不同网络中的另一台主机发送包,则要用主机标识符和网络标识符来定位此外部主机。这个定位网络和主机并发送包给它们的过程就叫做路由(,Routing,)。在网络中,一个路由器包含了一个,IP,层,来实现路径的选择,以及发送包到它们的目的地。,当数据被路由后,它在网络的传输过程中有可能丢失,所以底层的协议应该能够保证数据起始点到目的地的正确传递。,第,10,页,1-2-5 Internet,地址,Internet,地址分为,5,类,分别是,A,、,B,、,C,、,D,和,E,。每类地址各不相同,各自适应不同大小组织的需要。例如,,A,类地址用于超过,65,、,536,台主机的大型网络,,B,类地址用于超过,256,台但少于,65 536,台主机的中等规模的网络,,C,类地址用于最多,256,台主机的网络。,D,类地址被用于在一些,Internet,主机间进行多点传递,其范围为,224.0.0.0,239.255.255.255,。,E,类地址被预留,以便将来使用,其范围为,240.0.0.0,247.255.255.255,。,第,11,页,A,类地址,第,12,页,1-3,网络程序设计简介,IP,以两种形式存在着:,DNS,(域名服务)形式。,此外,,IP,地址在内部都表达成一个由,32,个二进制位(,bit,)构成的数字,所以,IP,地址的每一组数字都不能超过,255,。,第,13,页,1-3,网络程序设计简介,该程序只在,Windows 95,中进行了测试,但大家可以依次进入自己的“开始”、“设置”、“控制面板”、“网络”,然后进入“标识”选项卡。其中,“计算机名称”就是应在命令行中输入的内容。,第,14,页,1-3,网络程序设计简介,/:WhoAmI.java,/Finds out your network address when youre,/connected to the Internet.,package c15;,import.*;,public class WhoAmI,public static void main(String args),throws Exception,if(args.length!=1),System.err.println(,Usage:WhoAmI MachineName);,System.exit(1);,InetAddress a=,InetAddress.getByName(args0);,System.out.println(a);,/:,第,15,页,1-4,网络程序设计技术,Socket,RPC,网络程序设计特性,第,16,页,1-4-1 Socket,信息在一个进程的,Socket,和另一个进程的,Socket,间,以报文传输的形式进行交换。在发送端,Socket,,报文以队列的形式等待,直到网络协议传输它们。当报文到达后,它们又在接收端的,Socket,排队,等待接收进程以一定的系统调用来接收它们。在客户,/,服务器模式下,服务器是监听请求的进程,客户是发送请求的进程。一旦服务器进程接收到了请求,它就试图去处理该请求,并且将输出发送给客户。,第,17,页,1-4-2 RPC,RPC,(远程过程调用)诞生于,20,世纪,70,年代,它将计算机间的通信,看作是一个计算机调用另一个计算机的过程。在,RPC,方式中,所有报文都通过网络传递,每一个既可能请求,也可能应答一个过程的动作。,第,18,页,基于,RPC,的客户,/,服务器计算示例,第,19,页,1-4-3,网络程序设计特性,多用户应用程序 电子邮件(,Email,)是多用户应用程序的一个很好的例子。通过互联的单机系统,分布式计算使这样的应用程序成为可能。,资源共享 分布式计算使一个组织能够更好地利用物理资源。例如,办公人员可以共用一台价格昂贵的彩色打印机。,可升级性 由于分布式系统由许多组件构建而成,而且很有可能根据需要增加更多的组件,所以要具有可升级性。分布式系统可能要用于解决各种大小问题,所以要有随问题大小变化的能力。,有效性 在不同环境下,多平台能够得以应用,以解决每一个计算机的问题。,容错性和实用性 分布式应用程序的各组件,被配置为能够解决大多数的错误类型。,透明性 这个系统感觉上应为一个整体,而不是一系列独立组件的集合。这样,本地和远程对象可以使用同样的操作进行访问,而不需要知道它们的位置。,第,20,页,1-5 Java,支持的网络程序设计,第,21,页,1-5 Java,支持的网络程序设计,Socket,通过,Socket,通信,,Java,支持面向连接(,TCP,)和无连接(,UDP,)的协议。在本书的第一部分,将介绍任何使用,Socket,编写的分布式应用程序。,RMI,远程方法调用(,RMI,)允许程序编写分布式应用程序,在这个分布式应用程序中,远程,Java,对象的方法可以被运行于网络中不同主机上的,Java,虚拟机所调用。在这种模式下,参与通信的所有分布的对象必须用,Java,语言实现。如果它们以其他语言实现的话,,Java,对象就无法与网络上的其他对象进行通信。本书第二部分将讨论,RMI,,以及任何使用它去开发分布式应用程序。有关,RMI,的更多信息,请浏览,IDL Java IDL,让程序员能够用接口定义语言(,IDL,)定义远程接口(,IDL,是,OMG,组织定义的工业标准)。一旦程序员使用,IDL,定义了远程接口,那就可以使用特定的编译器编译该定义,以产生,Java,接口定义、客户桩(,stub,)和服务器构架(,skeleton,)。,Java IDL,允许一个,Java,客户透明地调用驻留在远程服务器上的,IDL,对象,并且允许介绍,CORBA,,以及如何使用,VisiBroker for Java,一个完整的,CORBA,实现,开发分布式应用程序。有关,Java IDL,的更多信息,请浏览,products/jdk/idl,。,第,22,页,1-5 Java,支持的网络程序设计,JavaSpaces JavaSpaces,是一种尝试,它想要帮助分布式应用程序开发者,以方便简单、快速的统一机制,去共享、协调、传送网络中分布的资源、服务和对象。,JavaSpaces,有它自己的私有元组空间(,tuple spaces,),其建立于著名的,Linda,原型的元组空间之上。这一原型最初是为并行处理系统开发的,作为一个全球通信的缓冲。有关,JavaSpaces,的更多信息,请浏览,Jini,是,Sun Microsystems,的一个,R,D,项目,它扩展了,Java,的能力,使,Java,能够支持更为广泛的网络设备。,Sun,设想使,Jini,成为一个系统,在此系统中,人们使用网络设备和服务,就像使用今天的电话一样简单。有关,Jini,的更多信息,请浏览,JavaPC,是一个软件系统,它提供了一个简单而又灵活的移植路径到,Java,平台和网络计算。,JavaPC,允许公司企业在运行,MS-DOS,和,Windows 3.x,的,PC,上配置使用,Java,应用程序,第,23,页,1-6,移动网络,当一个程序开始通过网络运行时,在网络和程序之间就产生一种新的关系。网络移动(,Network Mobile,)代码确保最终用户有必要的软件查看和使用通过网络发送的数据变得容易。,移动代理(,Mobile Agent,),是网络程序设计的一种改进方法。由于网络的可靠性不是很重要,所以它们是非常有吸引力的。,Java,支持网络移动开始于平台独立性和安全性两方面。,Java,的这两项功能使网络移动步入使用阶段。平台独立性使开发一个网络应用程序更为容易,因为开发人员不再需要为不同的平台开发不同版本的程序。,Java,的安全性则使得用户从不可靠的资源下载文件时更为有信心。,第,24,页,1-7 Java,安全性常识,Java,的安全模式包括,3,层:,Java,语言本身。,Java,编译器和,run-time,(运行时)系统。,SecurityManager,类。,第,25,页,1-7 Java,安全性常识,Java,编译器和,run-time,系统安全层提供了必要的功能,以确保,Java,系统不会因无效代码而崩溃。它提供了一个简单的、由以下,3,个子层所组成的安全的运行环境:,Java,字节代码解释器和类格式校验。,一个在运行时动态装载和检查库的机制。,自动的垃圾回收机制。,第,26,页,1-7 Java,安全性常识,第,27,页,1-8,本章小结,在网络通信中,,Java,不仅提供了面向连接和无连接数据报的底层通信,而且还提供了高层服务,如,E-mail,和,WWW,服务等。通过,Java,提供的网络功能,可以以流的方式来进行网络数据的传输,而且不需要关注连网的细节问题。在因特网上,已经开发了许多服务,如,WWW,浏览、,E-mail,等,而,Java,也提供了相应的扩展组件,如对于,E-mail,应用,,Java,提供了,JavaMail API,,使用时只需要调用其提供的方法就可以完成如发送邮件的操作。,Java,对数据报的支持与它对,TCP,套接字的支持大致相同,使用,DatagramSocket,类来表示无连接的,Socket,,接收和发送数据报。接收和要发送的数据报内容保存在,DatagramPacket,对象中。,第,28,页,1-9,实践检验,理论巩固,编程获取本机的,IP,地址。,Java,提供的网络功能有哪三大类?,Socket,是传统网络程序最常用的方式,他们是如何工作的?,如何通过,URL,读取,WWW,服务器上的数据?,URL,和,URLConnection,的区别是什么?,第,29,页,1-9,实践检验,上机实战,编程实现,Java,程序访问,cgi,程序,并传给它,10,个数据,,cgi,程序接收后,排序并传送回来。,编写一个会话程序,要求:会话双方可以自由通话,看到对方发来“,bye”,则退出。,第,2,章,网络程序设计的编程基础,第,30,页,主要内容,在没有网络的前提下测试程序,端口,套接字,TCP/IP,和,UDP/IP,通信,客户,/,服务器通信,Greetings,服务器实例,解析,Internet,地址,第,31,页,2-1,在没有网络的前提下测试程序,由于多种潜在的原因,我们可能没有一台客户机、服务器以及一个网络来测试自己做好的程序。我们也许是在一个课堂环境中进行练习,或者写出的是一个不十分可靠的网络应用。,IP,的设计者注意到了这个问题,并建立了一个特殊的地址,localhost,来满足非网络环境中的测试要求。在,Java,中产生这个地址最一般的做法是:,InetAddress addr=InetAddress.getByName(null);,为得到本地主机地址,也可向其直接传递字串,localhost,:,InetAddress.getByName(localhost);,或者使用它的保留,IP,地址(四点形式),就象下面这样:,InetAddress.getByName(127.0.0.1);,三种方法得到的结果是一样的。,第,32,页,2-2,端口,由,IP,表达的每台机器也包含了“端口”(,Port,)。我们设置一个客户机或者服务器的时候,必须选择一个无论客户机还是服务器都认可连接的端口。,注意端口并不是机器上一个物理上存在的场所,而是一种软件抽象(主要是为了表述的方便)。,系统服务保留了使用端口,1,到端口,1024,的权力,所以不应让自己设计的服务占用这些以及其他任何已知正在使用的端口。本书的第一个例子将使用端口,8080,(为追忆我的第一台机器使用的老式,8,位,Intel 8080,芯片,那是一部使用,CP/M,操作系统的机子)。,第,33,页,2-3,套接字,套接字”(,Socket,)也是一种软件形式的抽象,用于表达两台机器间一个连接的“终端”。,有两个基于数据流的套接字类:,ServerSocket,,服务器用它“侦听”进入的连接;以及,Socket,,客户用它初始一次连接。一旦客户(程序)申请建立一个套接字连接,,ServerSocket,就会返回(通过,accept(),方法)一个对应的服务器端套接字,以便进行直接通信。,创建一个,ServerSocket,时,只需为其赋予一个端口编号。不必把一个,IP,地址分配它,因为它已经在自己代表的那台机器上了。但在创建一个,Socket,时,却必须同时赋予,IP,地址以及要连接的端口编号(另一方面,从,ServerSocket.accept(),返回的,Socket,已经包含了所有这些信息)。,第,34,页,2-4 TCP/IP,和,UDP/IP,通信,对于,Socket,程序,你可以使用两种通信协议:数据报通信(,Datagram Communication,)协议和流通信(,Stream Communication,)协议。它们都被,Java,所支持。,第,35,页,2-4-1,数据报通信协议,数据报通信协议,如,UDP,,为无连接协议。这就意味着你可以在任何时候发送数据报,当然,你仍需要发送本地的,Socket,描述符及接收方的,Socket,地址。正如你所知道的,在每一次建立通信时,都要发送这些附加的数据。,第,36,页,2-4-2,流通信协议,流通信协议最广为人知的如,TCP,协议。与,UDP,不同,,TCP,是一个面向连接的协议。为了使用,TCP,协议进行通信,必须先在两个,Socket,之间建立连接。其中一个,Socket,监听连接请求(服务器),另一个发出连接请求。一旦两个,Socket,之间建立了连接,它们就能被用来双向(或单向)传递数据。,第,37,页,2-4-3 UDP,与,TCP,TCP,用于实现不受传输数据长度限制的网络服务,如远程登录,Telnet,、,FTP,等。,UDP,的复杂程度较低,需要的开销也较小。它主要使用在构建于局域网之上的分布式系统中,客户,/,服务器应用程序的实现。一般情况下,你最好使用,TCP,,因为它提供了可靠的、面向连接的通信方式。如果应用程序协议句柄可靠,应用程序需要广播,或者应用程序不能忍受,TCP,的开销,那么可以使用,UDP,。本书此部分的大多数实例,都使用,TCP,协议。,第,38,页,2-5,客户,/,服务器通信,数据流,TCP Socket,UDP Socket,(数据报),多点传送,Socket,第,39,页,客户,/,服务器的,Socket,通信,第,40,页,2-5-1,数据流,当读写,BufferedReader,和,BufferedWriter,缓冲区数据时,就减少了对源数据的访问量。注意,具有缓冲的流比没有缓冲的流效率更高。,FilterInputStream,和,FilterOutputStream,由一个非缓存的,InputStream,和,OutputStream,实例构造而成。它们通过缓存和刷新提高性能。,DataInputStream,和,DataOutputStream,为读写原始数据类型提供高级服务。,FileReader,、,FileWriter,、,FileInputStream,和,FileOutputStream,一起用于从文件中读,或写到文件中。,第,41,页,2-5-2 TCP Socket,通过,Socket,类可以建立,TCP Socket,连接。使用,Socket,编写客户或服务器程序需要以下,4,步:,打开一个,Socket,。,创建一个数据输入流。,创建一个数据输出流。,关闭,Socket,。,第,42,页,设计,Socket,打开一个,Socket,如果你是编写客户程序,要打开,Socket,,应该如下做:,Socket MyClient=null;,try,MyClient=new Socket(host,PortNumber);,catch(UnknownHostException uhe),uhe.PrintStackTrace();,catch(IOException e),e.printStackTrace();,如果你是编写服务器程序,要打开,Socket,,应该这样做:,public static finall int PortNumber=4000;,ServerSocket MyService=null;,try,MyService=new ServerSocket(PortNumber);,catch(IOException ioe),ioe.printStackTrace();,第,43,页,设计,Socket,当你实现服务器程序时,还要从,ServerSocket,产生一个,Socket,对象,以便监听和接受来自客户的连接。,Socket serviceSocket=null;,try,serviceSocket=MyService.accept();,catch(IOException ioe),ioe.printStackTrace();,第,44,页,创建一个数据输入流,BufferedReader is=null;,try,is=new BufferedReader(new InputStreamReader(MyClient.,getInputStream();,catch(IOException ioe),ioe.printStackTrace();,注意:如果你用的是,JDK 1.0.2,,则应使用,DataInputStream,类创建输入流,如下所示:,DataInputStream dis=null;,try,dis=new DataInputStream(MyClient.getInputStream();,catch(IOException ioe),ioe.printStackTrace();,第,45,页,在服务器端创建输入流,BufferedReader is=null;,try,is=new BufferedReader(new InputStreamReader(serviceClient.getInputStream();,catch(IOException ioe),ioe.printStackTrace();,第,46,页,创建一个数据输出流,DataOutputStrem os=null;,try,os=new DataOutputStrem(MyClient.getOutputStrem();,catch(IOException ioe),ix.printStackTrace();,第,47,页,使用,DataOutputStrem,类发送数据,DataOutputStrem os=null;,try,os=new DataOutputStrem(serviceClient.getOutputStream();,catch(IOException ie),ie.printStackTrace();,第,48,页,关闭,Socket,try,os.close();,is.close();,MyClient.close();,catch(IOException io),io.printStackTrace();,而在服务器端,代码应为:,try,os.close();,is.close();,serviceSocket.close();,catch(IOException ic),ic.printStackTrace();,第,49,页,2-5-3 UDP Socket,(数据报),UDP Socket,连接通过,DatagramSocket,类创建。,DatagramSocket,使用包发送和接收数据,它们被表示为,DatagramPacket,对象。为了使两个程序能够通过,UDP,连接相互对话,在它们的机器上,必须有到一个端口的,DatagramSocket,连接。这可以通过创建一个,DatagramSocket,对象来完成。,注意:在服务器代码中使用的,DatagramPacket,构造成员,只需要两个参数:一个是包含指定客户的字节数组,;,另一个是字节数组的长度。当我们如上面所示,构造一个,DatagramPacket,以通过,DatagramSocket,发送时,还必须提供包的目的地的,Internet,地址和端口号。,第,50,页,2-5-4,多点传送,Socket,多点传送组由,D,类(范围在,224.0.0.1,239.255.255.285,之间),IP,地址标识。将包广播给多个接收者有些类似于收音机和电视机广播。多点传送,IP,的一个实际应用就是,Internet,网上的音频和视频广播。,想要监听多点传送地址的进程首先创建一个,MulticastSocket,,然后通过调用,JoinGroup,()方法,加入多点传送的会话。,第,51,页,2-6 Greetings,服务器实例,%java SimpleServer,&,SimpleServer Started.,%java SimpleClient,please input a keyword,:,hello,Got from the Server,:,Sorry,you dont speak my protocol.,正确运行的情况如下:,%java SimpleServer,&,SimpleServer Started.,%java SimpleClient,please input a keyword,:,Greetings,Got from the Server:,:,.and salutations.,第,52,页,Greetings,服务器实例,服务器程序,客户程序,错误,第,53,页,2-6-1,服务器程序,服务器程序是非常简单的。它所要做的就是:产生一个,ServerSocket,对象和一个,Socket,对象,以接受客户的连接;产生一个输入流以便从客户机读信息;产生一个输出流,以便发送响应给连接的客户机。服务器程序如例,2.1,所示。注意,我们选择了大于,1023,的端口号,5000,来运行服务器。端口号,0,1023,被预留给了系统管理员运行的服务。,第,54,页,2-6-2,客户程序,客户程序也是非常简单的:它打开一个端口号为,5000,的,Socket,连接,此端口为服务器运行的端口;它使用一个输出流,dos,,发送信息到服务器;使用一个输入流,读来自服务器的信息(即应答)。,第,55,页,2-6-3,错误,如果你运行上述服务器和客户程序,会发现客户只能建立一个到服务器的连接。如果你再次运行客户程序,将得到出错信息“,Connection refused”,(拒绝连接)。事实上,上述的服务器程序在接受了一个客户的请求后就中止了,这一点需要注意。在下一章中,我们将讨论多线程服务器程序的开发,它能持续运行并正确处理多个客户在同一时间的请求。,第,56,页,2-7,解析,Internet,地址,GetName,GetIP,NsLookup,IPtoName,第,57,页,2-7-1 GetName,例,2.3,中的源代码显示了如何获得你所工作的机器的字符名。,InetAddress,是,包中的一个类。在例,2.3,中,,host,为,InetAddress,类型,语句,Host=InetAddress.getLocalHost,(),返回到,InetAddress,。例如,如果我的主机名为“,leo”,,,IP,地址为“,134.117.5.3”,,那么变量,host,将得到值“,leo/134.117.5.3”,。由于我们主要使用的是机器名,所以我们可以使用方法,getHostName,(),去输出机器名“,leo”,。,第,58,页,例,2.3,:,GetName.jave,import .*;,/*,*(#)GetName.java,*/,public class GetName,public static void main(String argv)throws Exception,InetAddress host=null;,Host=InetAddress.getLocalHost();,System.out.println(host.getHostName();,第,59,页,2-7-2 GetIP,Internet,地址是以数字表示的,通常称作,IP,地址。前面例子中,返回的是机器名(即主机名)。但是,你如果想返回,IP,地址,如,134.117.5.3,的话,可以修改上例,以返回你所工作主机的,IP,地址。,第,60,页,2-7-2 GetIP,方法,getAddress(),返回一个,4,字节的字节数组。例如,如果你的,IP,地址是,134.117.5.3,,那么在例,2.4,中定义的字节数组变量,ip,的值应为:,ip0=134,ip1=117,ip2=5,ip3=3,第,61,页,2-7-4 IPtoName,由于,InetAddress,类中的,getHostName(),方法存在一个,Bug,,所以使用,JDK 1.0.2,编写一个转换,IP,地址到字符名的程序并不是一项容易的工作。但是,在,JDK 1.1,中更正了这个,Bug,,所以例,2.6,中的代码应该运行于,JDK 1.1,或更高版本环境下。,第,62,页,第,3,章,客户和服务器程序设计,第,63,页,主要内容,对现有服务编写客户程序,使用线程进行编程,编写新的服务器和客户程序,第,64,页,3-1,对现有服务编写客户程序,SMTP,客户程序,finger,客户程序,ping,客户程序,第,65,页,3-1-1 SMTP,客户程序,SMTP,,即简单邮件传输协议(,Simple Mail Transfer Protocol,),它是,Internet,中被广泛用于发送邮件的一种协议。,SMTP,服务使用了,TCP,协议,运行于端口,25,。,SMTP,协议不很复杂,但是仍要掌握几个命令,以便更好地理解它的工作原理。下例为使用,Telnet,登录到一台运行,SMTP,服务的、端口号为,25,的机器上时,屏幕所显示的内容。,第,66,页,3-1-2 finger,客户程序,finger,是,Internet,服务之一,它用于确定当前哪一个用户登录到一台特定的计算机。另外,它也被用于探测更多的个人用户。,finger,协议在,RFC,规范的,1288,页有定义。,finger,服务器使用,TCP,协议,运行于端口,79,。当一个用户调用,finger,客户程序时,他通过需要提供用户,ID,。,第,67,页,3-1-3 ping,客户程序,ping,是,Packet InterNet Groper,的缩写,它是一个建立在,Unix,系统中的程序。它的作用是,通过向远程主机发送,ICMP echo,请求并等待一个响应,来检查远程主机是否可到达。,ICMP,(,Internet Control Message Procotol,)最初的设计目的是允许路由器报告传输错误的原因,以及允许路由器和主机发送错误或控制信息给远程的路由器和主机。,在,Unix,系统中,,ping,是通过向远程主机发送一个,ICMP echo,请求,并等待响应来实现的。如果响应中包含了在请求时所发送的数据,并且完全一致,就说明远程主机是可到达的。相反,如果路由器网关不能发送,echo,请求,那么它就返回一个不可到达信息(包括错误代码)给主机。,第,68,页,3-1-3 ping,客户程序,第,69,页,3-2,使用线程进行编程,线程,线程的优点,创建和运行线程,创建和启动线程,使线程睡眠,控制线程,改变线程优先级,同步,第,70,页,序列程序,第,71,页,具有两个线程的程序,第,72,页,3-2-1,线程,“,线程”(,Thread,)一词来源于操作系统中的短语,Thread of execution,。在单线程的情况下,在任一时刻,只有一个单点执行。而如果在一个程序中使用多线程,那么就意味着,在任一给定时刻,程序有多点在执行。,线程能够产生新的线程并且结束它们。新产生的线程运行于同一个地址空间,并且被允许共享数据。,第,73,页,3-2-2,线程的优点,使用线程时,会发现它具有许多优点。首先,它使程序能够同时执行多个任务。另外,它们提供了一个充分利用多,CPU,计算机的方法。下面是一个如何同时进行多任务的示例:假定要去读用户通过键盘输入的一行文本,这时程序就要终止,直到用户输入完毕。如果这时程序没有其他工作要做,那么这样没有什么问题。但如果程序这时还要做一些后台工作,例如绘图或制作动画等,那么就不得不等待该行文本输入完毕,,CPU,空闲下来才能进行。在这种情况下,就可以利用线程,在程序等待用户输入文本时,完成后台工作。,线程的其他优点还包括,它能够提高应用程序的吞吐率,加快应用程序的响应时间,以及使应用程序更有效地利用系统资源。,第,74,页,3-2-3,创建和运行线程,注意:如果运行例,3.4,代码得到的结果与本文不同,不要太诧异,因为线程是与机器相关的。在不同的机器上,线程运行的顺序并不能保证相同。参见,3-2-7,节有关线程运行次序和优先级的介绍。,第,75,页,3-2-4,创建和启动线程,创建线程有两种方法,一个方法是从一个自定义的类(例如,MyThread,)中创建一个对象,这个类扩展了上文所述的,Thread,类。,MyThread,类中必须替换,Thread,类中的,run(),方法,这可以通过提供一个,Implementation,来实现。,需要注意的是,初始化,MyThread,类(如,MyThread t1=new MyThread,(“,read”,);)并不能使对象,t1,作为一个线程开始执行,而必须调用线程的,start(),方法以开始线程的执行。一旦,start(),方法被调用,它将依顺序调用,run(),方法。,run(),方法中,包括了线程所要执行的所有操作。,这种创建线程的方法有一个缺陷,即必须扩展,Thread,类。由于,Java,不支持多重继承,所以不能写一个多线程的,Applet,。因为如果要写多线程的,Applet,的话,就要扩展,Applet,和,Thread,类,而这在,Java,中是不允许的。由于这个原因,,Java,给出了另一种创建线程的方法。,第,76,页,3-2-4,创建和启动线程,创建线程的另一种方法是使用接口。在,Java,中,用于创建线程的接口是,Runnable,,它的定义如下:,package java.lang;,public interface Runnable,public abstract void run();,这个接口中仅定义了一个方法,即,run(),方法。它被声明为,abstract,,这意味着这个接口的执行者必须执行,run(),方法。使用这个接口,同样可以实现上一个例子,第,77,页,3-2-5,使线程睡眠,假定一个绘图的方法以单线程方式运行,并且想要控制该线程绘制一个对象的速度。为做到这一点,可以在线程要绘制对象时,通过简单的挂起(,Suspend,)来实现。另外,也可以使用,sleep(),方法,通过使该线程睡眠,来暂停其一段运行时间。,sleep,的参数就是线程睡眠的毫秒数。注意,,sleep,方法抛出一个异常(,InterruptedException,),应该捕获该异常。,第,78,页,3-2-6,控制线程,而要控制线程的执行,则可以使用,Thread,类中的,3,个方法:,stop(),,,suspend(),和,resume(),。
展开阅读全文