已阅读5页,还剩114页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第11章 Java网络通信程序的设计,11.1 处理URL内容 11.2 使用Socket通信 11.3 使用UDP通信,11.1 处理URL内容,URL(Uniform Resource Locator)是Internet的关键部分,它提供了人和机器的导航,其功能是指向计算机里的资源,即定位。URL可以分成三个部分:通信协议、计算机地址和文件。URL常见的通信协议有三种:http,ftp和file。所谓通信协议,就是客户端计算机与服务器端计算机在网络上通信的方法。,有时候在地址后面还要指定使用哪一个端口(Port),例如:80/index.html。如果URL没有指定使用哪一个端口,则会根据通信协议使用默认的端口。一般地,http协议默认端口为80,ftp协议默认端口为21。 包中包含两个专门用于URL的关键类,即URL和URLConnection。URL和URLConnection类封装了检索远程站点信息的操作,因而大大地降低了这些操作的复杂性。下面几节将介绍这两个类。,11.1.1 URL类的基本方法 URL类提供的最基本的网络功能是以流的形式读取URL所指的的数据。URL类的实例可以用表示URL的文本串来建立,以表示URL所指的数据。构造一个URL类实例的最简单方法是为URL构造方法赋予一个字符串: URL url = new URL(/index.html); 这被称为“绝对”URL,因为赋予的字串指定了从协议到资源名的全部内容。另一种URL类的构造方法是构造一个“相对”URL: URL data = new URL(url, “data/data.html“);,这种构造方法指定了位于url的data子目录中的data.html文件,它的绝对地址应该是/data/data.html。 这两种构造方法都可以指定一个URL,如果指定的URL是错误的,构造方法会抛出一个运行时错误:MalformedURLException,这个Excetion通知用户构造了一个形式错误的URL。,注:URL类既支持http协议,也支持ftp和file协议。如果URL文本有错或者Java平台不支持其协议部分,则这个构造函数抛出一个MalformedURLException,该Exception是java.io.IOException的子类,指出给定的是不合法的URL。通常应通过try-catch块处理或声明让调用方法传递这个异常。,URL类常用的构造函数有下列三种: URL(String spec) throws MalformedURLException 创建一个由spec指定的URL类的实例。 URL(String spec, String host, int port, String file) throws MalformedURLException 创建一个URL类的实例,分别指定其通信协议(protocal)、计算机地址(host)、连接端口(port)和文件(file)。如果port值是-1,则表示使用默认端口。, URL(String protocal, String host, String file) throws MalformedURLException功能同上,但没有指定端口,即使用默认的端口。 URL类的一些主要方法如下: public String getFile():返回URL中的文件部分。 public String getHost():返回URL中的计算机地址部分。 public int getPort():返回URL中所使用的端口。 public String getProtocal():返回URL中通信协议的部分。,下面是一个使用URL类及其方法的例子。 例11.1 URLDemo.java import genesis.*; import .*; public class URLDemo public static void main(String args) try ,/ 创建一个指向首页的URL类的实例 URL url = new URL(“/index.html“); Transcript.println(“Protocol: “ + url.getProtocol(); Transcript.println(“Host: “ + url.getHost(); Transcript.println(“Port: “ + url.getPort(); Transcript.println(“File: “ + url.getFile(); catch(MalformedURLException e) Transcript.println(“错误的URL!“);, 这个例子很简单,因为没有指定URL的连接端口,所以显示值为-1。实际连接时,会根据通信协议而决定使用哪一个端口。它的运行结果如图11.1所示。,图 11.1,11.1.2 用URL类实现页面的访问 一旦构造了URL,就可以用URL类中的openStream()方法读取URL描述的数据。openStream()打开一个到URL类指定资源的连接,并返回一个InputStream对象。利用这个对象,可以方便的读取资源的内容,也可以链接到其他类型的输入流和读取器上。 我们来看一个读取页面内容的例子。 例11.2 GetPage.java import genesis.*; import java.io.*; import .*;,public class GetPage public static void main(String args) try URL url = new URL(“/index.html“); InputStream in = url.openStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in);,/ 打开index.hmtl文件为写做准备 FileWriter fw = new FileWriter(“index.html“); PrintWriter pw = new PrintWriter(fw); String line; / 逐行读入页面内容 while (line = reader.readLine() != null) / 将读入的行保存到index.html文件 pw.println(line); / 将读入的行显示在窗口中 Transcript.println(line);, reader.close(); pw.close(); fw.close(); catch(IOException e) Transcript.println(e.getMessage(); 程序的运行结果如图11.2所示。,图 11.2,上面的例子通过读取的首页index.html,展示了怎样通过URL访问Web页面的内容。图11.2窗口中显示的就是index.html页面所包含的内容(即它的源码)。该例中将读入的内容保存在当前目录下,名为index.html的文件中,用浏览器打开这个文件,可以看到如同访问的页面。但是,无法看到页面中的图片,因为打开的输入流只读入了页面的内容,并没有将图片链接也读入进来。打开index.html文件将看到如图11.3所示的页面。,图 11.3,11.1.3 用URLConnection类实现页面的访问 我们已经知道了如何通过URL类访问URL资源,但如果想了解关于这个资源的更多信息,就需要使用URLConnection类。URLConnection类提供了访问网络资源时更多、更好的控制方法。 使用URLConnection类来访问Web页面的步骤如下: (1) 调用URL类的openConnection()方法得到一个URLConnection类的实例: URLConnection conn = url.openConnection(); (2) 调用以下方法,设置所有相关属性:, setAllowUserInteraction() setDoInput() setDoOutput() setIfModifiedSince() setUseCaches() setRequestProperty() (3) 调用connect()方法连接远程资源: conn.connect(); connect()方法除了创建一个连接指定服务器的套接字连接外,还可以查询服务器以获取相应头信息(header information)。,(4) 连接服务器以后,使用getHeaderFieldKey()和getHeaderField()方法来枚举出头信息的所有域。此外,也可以使用如下的方法来查询标准域的内容: getContentEncoding() getContentLength() getContentType() getData() getExpiration() getLastModified(),(5) 使用getInputStream()方法访问资源数据。用getInputStream()方法将返回一个输入流,此输入流和URL类的openStream()方法返回的输入流是相同的。 下面我们将详细的介绍其中的一些方法。在用于连接服务器前设置连接属性(第(2)步)的几个方法中,setDoInput()和setDoOutput()这两个方法最为重要。缺省时,连接服务器后将产生一个用于读取服务器数据的输入流,但不会产生用于向服务器写出数据的输出流。如果需要用到一个输出流(例如,用于向CGI Form发送数据),就必须调用 conn.setDoOutput(true);,setIfModifiedSince()方法用于告诉连接:只需要在给出的日期之后被修改过的数据。 setUseCaches()和setAllowUserInteraction()方法只用于Applet。setUseCaches()方法指示浏览器先检查它的高速缓存区,这样可以优化访问,如果设置其值为false,将不使用浏览器的缓存,其默认值为true。setAllowUserInteraction()允许Applet弹出一个查询用户名和密码的对话框。这些设置在Applet外部不起作用。 setRequestProperty()方法设置一个名字/值对,用于说明某一特定的协议。例如,想访问一个口令保护的网页,必须进行如下设置:,String input = username +“: “+ password; conn.setRequestProperty(“Authorization“, “Basic “ + input); 注:用ftp协议访问一个有口令保护的文件时,将使用和上面完全不同的方法,只需要创建一个如下形式的URL: ftp:/username:/pub/file.txt 当调用了connect()方法后,就可以查寻响应头信息。我们通过下面的例子来介绍如何获得头信息的所有域和值以及页面内容。,例11.3 GetHeaderField.java import genesis.*; import .*; import java.io.*; public class GetHeaderField public static void main(String args) try, URL url = new URL(“/index.html“); / 得到一个URLConnection对象 URLConnection conn = url.openConnection(); / 连接服务器 conn.connect(); int i = 1; String key = “; String value = “;,/ 逐一读出指定URL中的所有域 while (key = conn.getHeaderFieldKey(i) != null) / 读出对应域的值 value = conn.getHeaderField(i); Transcript.println(key + “: “ + value); i+; / 获取一个输入流 InputStream in = conn.getInputStream();,BufferedReader reader = new BufferedReader(new InputStreamReader(in); / 打开index.hmtl文件为写做准备 FileWriter fw = new FileWriter(“index.html“); PrintWriter pw = new PrintWriter(fw); String line = “; / 逐行读入页面内容 while (line = reader.readLine() != null), / 保存到index.html文件中 pw.println(line); reader.close(); pw.close(); fw.close(); catch(IOException e), Transcript.println(e.getMessage(); 程序的运行结果如图11.4所示。,图 11.4,以上输出结果展示了一个典型的HTTP请求的响应头所包含的一组域。getHeaderFieldKey()和getHeaderField()方法分别返回响应头中指定位置的域名和值。指定值基数为1,当指定值为零或大于头中域总数时,将返回null串。由于URLConnection类中没有提供获得相应头中域总数的方法,所以需重复调用getHeaderFieldKey()方法,直到返回null串来确定头中域的总数。,程序中同时演示了如何通过URLConnection类获取页面内容。调用URLConnection类的方法getInputStream()将返回一个InputStream类的实例,这个对象和调用URL类中openStream()返回的InputStream对象是相同的。利用这个对象,我们可以建立一个获取页面内容的输入流。运行例子后,当前目录将会生成一个index.html文件,通过浏览器打开这个文件,可以看到,结果和前面通过URL访问页面内容所得到的结果相同。 此外,为了便于查询最常见的响应头域的值,Java库提供了六个更为方便的方法直接访问这些域,如表11.1所示。,表11.1 直接获取指定域值的方法,11.1.4 与CGI的沟通 在Java技术出现之前,用CGI(Common Gateway Interface)来提供相互交换网络数据的方法就已广泛使用。把信息从网络浏览器发送给相应的网络服务器,例如使用电子邮件服务,通常需要填写用户名和提交密码。传统的HTML语言提供了Form标记发送格式数据。一个典型的HTML Form描述如例11.4。,例11.4 form.html Name: ,Email Address: 通过在浏览器上打开输入以上代码的html文件,我们可以看到一个如图11.5所示的页面。,图 11.5,在Internet上访问邮件服务时, 用户需要填写一个类似上图的表单。当用户点击提交按键后,浏览器将会发送这些填写的数据到action属性指定的服务器中的CGI程序。CGI程序负责处理这些数据,然后生成一个HTML页面,并送回浏览器。对于邮件服务,这个新的响应页通常就是我们登陆后的页面。(有关CGI程序和HTML Form的详细内容,本章将不再继续讨论,如需了解可参考有关书籍),除了处理传统的非交互式类型外,URLConnection类也提供了用于CGI或Servlet连接的功能。和HTML表单页一样,Java程序可以向服务器发出一个CGI请求,这个请求既可以设为GET,也可以设为POST。此外,也可在程序中拦截CGI程序的输出,所以通过Java程序可以实现和CGI程序交互信息的全部过程。,通过GET方法向CGI程序发送信息时,只需将参数置于URL的末尾,并用“?”分隔。URL的基本格式为 http:/host/script?parameters 当包含两个以上的参数时,用一个“&”分开每个参数,并对参数做以下的编码处理:用“+”代替所有的空格,用%加两位十六进制数代替所有非字母的字符(包括汉字)。例如,假设一个参数为“C+ Language”,它将被编码为“C%2b%2b+Language”,其中2b(十进制数43)就是ASCII码的“+”字符。这种编码方法避免了空格干扰,并可以解释其他字符,这种编码方式称为URL编码。,GET方法非常方便,但是有一个大的限制,就是浏览器一般会限制GET请求的URL串的字符个数。而POST的方法则不同,使用POST请求的时候,不把参数放在URL的末端,而是采用建立一个到服务器的输出流的方式。通过得到一个来自URLConnection的输出流,并把参数名/值对逐个写入到输出流,就可以实现POST方法的请求。使用POST方法时,仍需用URL编码方式处理这些输入的参数,并用“&”将参数分开。,下面我们仍然通过一个例子来详细的了解GET和POST方法与CGI通信的过程以及它们的不同之处。 例11.5 CGITest.java import genesis.*; import java.io.*; import .*; import java.util.*; public class CGITest ,URL url = null; URLConnection conn = null; FileWriter fw = null; PrintWriter pw = null; public static void main(String args) CGITest test = new CGITest(); ArrayList param = new ArrayList(); if (args0.equals(“GET“) | args0.equals(“get“), / GET方法所需要的参数 param.add(“p“); param.add(args1); param.add(“u“); param.add(“B“); / GET方法通过Yahoo提供的搜索引擎搜索给定的关键字 test.doGet(“/search“, param); ,if (args0.equals(“POST“) | args0.equals(“post“) / POST方法所需要的参数 param.clear(); param.add(“user“); param.add(args1); param.add(“pass“); param.add(args2); param.add(“type“);,param.add(“0“); param.add(“verifycookie“); param.add(“y“); / POST方法登陆163邮箱 test.doPost(“/cgi/163/login_pro.cgi“, param); ,public String doGet(String location, java.util.List param) if (param != null) StringBuffer bufParam = new StringBuffer(); / 通过一个枚举器列出所有参数 Iterator iterator = param.iterator(); String key = null; String value = null;,/ 枚举出所有的参数 while (iterator.hasNext() key = (String)iterator.next(); value = (String)iterator.next(); / 对参数进行编码,然后转化成key=value的格式 / 并将它们串在一起,通过,if (iterator.hasNext() bufParam.append(“,try url = new URL(location); conn = url.openConnection(); / 连接服务器 conn.connect(); / 得到一个输入流 InputStream in = conn.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in);,/ 打开Get.html文件准备写 fw = new FileWriter(“Get.html“); pw = new PrintWriter(fw); String line = “; / 逐行读入 while (line = reader.readLine() != null) page.append(line + “n“); pw.println(line);, pw.close(); fw.close(); reader.close(); in.close(); catch(IOException e) Transcript.println(e.getMessage(); ,return page.toString(); public String doPost(String location, java.util.List param) StringBuffer page = new StringBuffer(); try url = new URL(location); conn = url.openConnection();,/ 同时打开到服务器的输入和输出流 conn.setDoOutput(true); conn.setDoInput(true); if (param != null) / 获取一个到服务器的输入通道 PrintWriter out = new PrintWriter(conn.getOutputStream(); Iterator iterator = param.iterator();,String key = null; String value = null; / 枚举列出所有参数 while (iterator.hasNext() / 对参数进行编码,并逐个将参数转化成 / key=value的格式,直接输出到服务器 key= URLEncoder.encode(String)iterator.next(); value= URLEncoder.encode(String)iterator.next();,out.print(key + “=“ + value); if (iterator.hasNext() out.print(“,/ 获取一个输入流 InputStream in = conn.getInputStream(); BufferedReader reader = newBufferedReader(new InputStreamReader(in); / 打开Post.html准备写 fw = new FileWriter(“Post.html“); pw = new PrintWriter(fw); String line = “; / 逐行读入,while (line = reader.readLine() != null) page.append(line + “n“); pw.println(line); pw.close(); fw.close(); reader.close(); in.close();, catch(IOException e) Transcript.println(e.getMessage(); return page.toString(); ,这个例子比较长,但它并不复杂。程序中,通过两个方法:doGet()和doPost()分别实现了GET和POST两种方式与CGI的通信。在doGet()方法中,测试的是使用Yahoo提供的搜索引擎;在doPost()方法中,测试的是登陆163.net的免费邮件系统。 编译这个程序后,测试doGet()方法,可以用下面的命令行运行它: java CGITest get Java,产生的结果将保存在一个叫Get.html的文件中。用浏览器打开它,可以看到同在上的搜索引擎中输入“Java”搜索产生的页面相同的效果。doGet()方法需要提供两个参数,第一个参数是创建交互的CGI程序的URL,第二个参数是一个List模板类,里面存放了提供的参数。要注意的是,把这些参数串在一起并接在URL的末尾时,必须用URLEncoder类的encode()方法对参数进行URL编码。,如果要测试doPost()方法,须通过下面的命令行运行这个程序: java CGITest post Username Password 要测试登陆163.net的免费邮箱,就必须在163.net上注册一个邮箱,并在命令行的第2、3个参数提供登陆邮箱的用户名和密码。产生的结果保存在一个叫Post.html的文件中。同样,浏览这个文件看到的同在网站上登录免费邮件系统所看到的页面一样。,doPost()方法同样需要提供交互用的URL和保存参数的List,但是这里我们没有把参数串在一起,而是通过URLConnection类的getOutputStream()方法打开输入流,逐个将参数写入到输出流中。这样无论有多少参数也没关系了,但要注意的是,仍然要对参数进行URL编码并用“&”将它们分开。,注:由于各网站的CGI程序URL和参数可能会随着网站的 程序修改而改变,所以这个程序并不能保证一直得到正确的结果,但是只需查看网站的源代码,并找到HTML Form的action以及input的所有参数,对上面例子中的程序略作修改,就可以顺利的得到正确结果了。,11.2 使用Socket通信,URL和URLConnection类提供给我们一种简便的方法编写网络程序,实现一些较高级的协议访问Internet。但是通常,这些协议是不够的,我们常需要用一种更通用、更底层的方法编写网络应用程序,这就是我们最常用的套接字(Socket)通信。,11.2.1 InetAddress类 Internet上的每一台计算机都拥有一个惟一的地址,这样才能和其他网络上的计算机互通信息。我们常说的TCP/IP中的IP(Internet Protocal)。就是定义Internet上计算机的地址的。我们知道,一个IP地址必须由四个0255之间的数字组成,数字之间用点隔开。由于很难记忆这个由四个数字组成的地址,所以有了主机名(host name)的出现,例如,就是一个主机名。InetAddress就是用来实现IP的类。,InetAddress 类的声名如下: public final class InetAddress extends Object implements SerializableInetAddress类没有提供任何构造函数,我们只能通过它本身提供的一些静态方法来建立一个它的实例。通常,用于建立一个InetAddress类的方法有如下几种: public static InetAddress getByName(String host) throws UnknowHostException指定主机名建立一个InetAddress的实例。, public static InetAddress getByAddress(byte addr) throws UnknowHostException指定IP地址建立一个InetAddress的实例。 public static InetAddress getLocalHost()throws UnknowHostException建立本机的InetAddress的实例。 下面我们通过一个实例来看看如何使用InetAddress类。,例11.6 InetAddressDemo.java import genesis.*; import .*; public class InetAddressDemo public static void main(String args) try ,InetAddress addr1 = InetAddress.getByName(““); Transcript.println(addr1.getHostAddress(); InetAddress addr2 = InetAddress.getByAddress(addr1.getAddress(); Transcript.println(addr2.getHostName(); Transcript.println();,InetAddress addr3 = InetAddress.getLocalHost(); Transcript.println(addr3.getHostName(); Transcript.println(addr3.getHostAddress(); catch(UnknownHostException e) Transcript.println(e.getMessage(); 程序的运行结果如图11.6所示。,图 11.6,从运行结果我们可以看到,调用getByName()方法通过主机名建立一个InetAddress类的实例后,我们就可以得到对应于这个主机名的地址。需要注意的是,在调用建立InetAddress实例的几个静态方法时,这些方法会连接指定的地址或域名,如果无法连通,会抛出一个UnknowHostException,所以必须用try-catch块包含这个方法,并处理无法连通的情况。,11.2.2 客户端Socket类 TCP/IP最主要的功能是提供点对点通信机制。一个机器要在网络上与另一台机器通信,就需要建立一个互联的通道。这个通道传输两个数据流,一个为发出的数据流,一个为接收的数据流。由于有了IP地址,我们可以方便的在Internet上找到另一台机器。假如自己的机器要和另一台机器通信,就必须向那台主机发起一个连接请求。如果这个请求被接受,这次通信过程就开始了。通常情况下,我们把发起请求的机器叫客户端,被请求的机器则称为服务器。,Socket类是用来编写客户端程序的类。Socket类的声明如下: public class Socket extends Objects Socket类常用的方法有下列几种: Socket(InetAddress address, int port) throws IOException建立一个Socket的实例,用来连接指定的地址和端口。 Socket(String host, int port) throws UnknowHostException, IOException和上面类似,但是通过主机名代替InetAddress。, public void close() throws IOException 中断该Socket连接。 public InetAddress getInetAddress() 返回该Socket实例所连接的地址。 public InputStream getInputStream() throws IOException 返回一个输入流,用来接收服务器端发送的信息。 public OutputStream getOutputStream() throws IOException返回一个输出流,用来向服务器端发送信息。, public int getPort() 返回该Socket实例连接远程的端口。 public int getSoTimeout() throws SocketException 返回接收信息的时间限制。如果返回值为0,则表示没有限制。 public void setSoTimeout(int timeout) throws SocketException,设置接收信息的时间限制,以千分之一秒为单位。利用InputStream接收信息时,程序会一直挂起,直到接收到信息,或者到达时间限制为止。如果出现超时,则会抛出一个java.io.InterruptedIOException。如果timeout设为0,则没有时间限制,程序会一直挂起等待。 下面来看一个简单的Socket编程的示例。 例11.7 SocketDemo.java import genesis.*; import java.io.*; import .*;,public class SocketDemo public static void main(String args) try / 构造一个连接到时间服务器time-A. / 端口13的Socket类实例。 Socket sock = new Socket(“time-A.“, 13);,/ 从Socket获得一个接收服务器信息的输入流 BufferedReader in = new BufferedReader( new InputStreamReader(sock.getInputStream(); while(true) String line = in.readLine(); if (null = line) break; else,Transcript.println(line); catch(IOException e) Transcript.println(e.getMessage(); 程序的运行结果如图11.7所示。,图 11.7,这个例子非常简单,它打开了一个Socket类,这个Socket类连接到时间服务器time-A.的13端口上。当连接成功后,Socket类的getInputStream()方法返回一个InputStream对象,然后程序把流对象链接到一个BufferedReader上。接着就可以用readLine()方法读取服务器发送的所有字符,并把它们输出到屏幕上。直到readLine()方法返回null,即读完所有服务器发送的信息,程序才会结束。在Windows命令行下输入telnet time-A. 13,可以看到和上面类似的输出结果,如图11.8所示。,图 11.8,11.2.3 服务器端ServerSocket类 前面实现了一个简单的网络客户程序,它可以从服务器上接收信息,下面我们学习实现服务器端的编程方法。一个服务器程序启动后,通常会监听某一个端口,等待某一台客户端计算机发出连接的请求,然后作出反应。ServerSocket类的声明如下: public class ServerSocket extends Objects ServerSocket类的大部分方法都和Socket类的类似,它最常用的构造方法如下: ServerSocket(int port) throws IOException,创建一个ServerSocket示例是不需要指定IP地址的,SeverSocket总是处于监听本机端口的状态。 下面我们看一个服务器程序的示例。 例11.8 ReversalServer.java import java.io.*; import .*; public class ReversalServer public static void main(String agrs), try / 创建一个监听8189端口的ServerSocket ServerSocket s = new ServerSocket(8189); / 启动ServerSocket的监听 Socket insock = s.accept(); / 建立输入流通道 BufferedReader in = new BufferedReader( new InputStreamReader(insock.getInputStream();,/ 建立输出流通道 PrintWriter out = new PrintWriter(insock.getOutputStream(), true/*autoFlush*/); out.println(“Enter quit to exit.“); while(true) String line = in.readLine(); if (null = line) continue;,if (line.trim().equals(“quit“) break; else / 翻转输入的字符串 StringBuffer rline = new StringBuffer(); for (int i = line.length(); i 0; i-) rline.append(line.charAt(i - 1); out.println(“Reversed: “ + rline.toString(); ,out.close(); in.close(); insock.close(); catch(IOException e) e.printStackTrace(); ,上面的例子是一个简单的服务器程序,它启动了一个ServerSocket监听本机的8189端口,这个端口一般不会被用到。当有其他客户端请求与它联接时,accept()方法将接受这个请求并创建一个独立的Socket实例。通过这个实例,我们可以取得输入和输出的两个流。程序首先通过输出流向客户端发送了一条问候信息: out.println(“Hello! Please input. Enter quit to exit.“);,然后,服务器程序接收来自客户端的输入。每次从客户端读取一行信息,就将这些输入的字符串翻转以后再送回给客户端,所以这个服务器程序叫做ReversalSever。 编译并运行这个程序,然后在Windows命令行下输入“telnet 8189”。IP地址是一个特殊的地址,称为本机回送地址(Local Loopback Address),它代表着本机。,由于运行服务器程序的机器和启动telnet测试的是同一主机,所以这个地址也正是我们要连接的。当然,也可以从其他机器上启动telnet来测试这个服务器程序,这时候就必须telnet到运行服务器程序的IP地址上。启动telnet以后,输入任何信息,看看结果是不是你想象的,最后输入quit结束连接。此处如输入“123456”,则结果如图11.9所示。,图 11.9,11.2.4 多客户通信机制 我们注意到,前面例子中的服务器程序只能服务于一个客户端,也就是说,一个客户连接到这个服务程序后,将一直独占它。而通常情况下,我们看到的服务器总是要服务于许许多多的客户端的,比如一个网页服务器,可以接受许多客户的浏览。利用线程的特性,我们就可以很好地解决服务于多个客户的问题。,我们只需要对上面的程序做少许修改,就可以使它服务于多个客户端。首先,应该把主程序部分放入一个循环,每接收到一个来自客户端的请求,就启动一个线程来处理他。而主程序则可以继续等待来自其他客户端的请求。 下面看修改以后的程序,可试着启动多个telnet连接它进行测试。,例11.9 ThreadedReversalServer.java import java.io.*; import .*; public class ThreadedReversalServer public static void main(String agrs) int i = 0;,try / 创建一个监听8189端口的ServerSocket ServerSocket s = new ServerSocket(8189); for (;) / 启动ServerSocket的监听 Socket insock = s.accept(); System.out.println(“Thread “ + i + “ run.“); / 启动处理客户端信息的线程,new ThreadReversal(insock, i).start(); i+; catch(IOException e) e.printStackTrace(); ,class ThreadReversal extends Thread private Socket sock; private int counter; public ThreadReversal(Socket s, int i) sock = s; counter = i; ,public void run() try / 建立输入流通道 BufferedReader in = new BufferedReader( new InputStreamReader(sock.getInputStream(); / 建立输出流通道 PrintWriter out =,new PrintWriter(sock.getOutputStream(), true/*autoFlush*/); out.println(“Hello! Pl
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 上门维修服务合同三篇
- 【教学设计】《习作例文与习作》
- 申请律师执业人员个人总结
- 室内设计师个人实习总结
- 2026下半年年高校学生事务专职辅导员招聘考试笔试试题(含答案)
- 液压支架维修试题含答案
- 行政复议法考试试题及答案解析
- 新《保险法》试题及答案
- 中小学生假期劳动实践安全指导 课件
- 亲子居家安全知识互动课堂
- 宁波民营经济发展历程
- 安徽省A10联盟2026届高三上学期9月联考化学试卷(含答案)
- 人工智能+智慧城市停车场系统布局可行性分析报告
- 压疮品管圈课件
- 2025年北森笔试题型及答案
- GB/T 15620-2025镍及镍合金实心焊丝和焊带
- 秋季咳嗽健康讲堂
- 企业易制毒化学品管理(企业)
- JG/T 574-2019纤维增强覆面木基复合板
- JJF 2189-2025铂电阻温度计用精密测温仪校准规范
- 《团队合作》课件
评论
0/150
提交评论