友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第131部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


    }   

    l。setText(〃Ready to send your email address〃);  

  }  

  public boolean action (Event evt; Object arg) {  

    if(evt。target。equals(send)) {  

      if(pl != null) {  

        // pl。stop(); Deprecated in Java 1。2  

        Thread remove = pl;  

        pl = null;  

        remove。interrupt();  

      }  

      l2。setText(〃〃);  

      // Check for errors in email name:  

      str = t。getText()。toLowerCase()。trim();  

      if(str。indexOf(' ') != …1) {  

        l。setText(〃Spaces not allowed in name〃);  

        return true;  



                                                                                          557 


…………………………………………………………Page 559……………………………………………………………

      }  

      if(str。indexOf(';') != …1) {  

        l。setText(〃mas not allowed in name〃);  

        return true;  

      }  

      if(str。indexOf('@') == …1) {  

        l。setText(〃Name must include '@'〃);  

        l2。setText(〃〃);  

        return true;  

      }  

      if(str。indexOf('@') == 0) {  

        l。setText(〃Name must preceed '@'〃);  

        l2。setText(〃〃);  

        return true;  

      }  

      String end =   

        str。substring(str。indexOf('@'));  

      if(end。indexOf('。') == …1) {  

        l。setText(〃Portion after '@' must 〃 +  

          〃have an extension; such as '。'〃);  

        l2。setText(〃〃);  

        return true;  

      }  

      // Everything's OK; so send the name。 Get a  

      // fresh buffer; so it's zeroed。 For some   

      // reason you must use a fixed size rather  

      // than calculating the size dynamically:  

      byte'' sbuf =   

        new byte'NameCollector。BUFFER_SIZE';  

      str。getBytes(0; str。length(); sbuf; 0);  

      DatagramPacket toSend =  

        new DatagramPacket(  

          sbuf; 100; hostAddress;  

          NameCollector。COLLECTOR_PORT);  

      try {  

        s。send(toSend);  

      } catch(Exception e) {  

        l。setText(〃Couldn't send datagram〃);  

        return true;  

      }  

      l。setText(〃Sent: 〃 + str);  

      send。setLabel(〃Re…send〃);  

      pl = new Thread(this);  

      pl。start();  

      l2。setText(  

        〃Waiting for verification 〃 + ++vcount);  

    }  

    else return super。action(evt; arg);  

    return true;  

  }  

  // The thread portion of the applet watches for  

  // the reply to e back from the server:  



                                                                                        558 


…………………………………………………………Page 560……………………………………………………………

  public void run() {  

    try {  

      s。receive(dp);  

    } catch(Exception e) {  

      l2。setText(〃Couldn't receive datagram〃);  

      return;  

    }  

    l2。setText(new String(dp。getData();  

      0; 0; dp。getLength()));  

  }  

} ///:~  

  

程序片的UI (用户界面)非常简单。它包含了一个TestField (文本字段),以便我们键入一个电子函件地 

址;以及一个Button (按钮),用于将地址发给服务器。两个Label (标签)用于向用户报告状态信息。  

到现在为止,大家已能判断出DatagramSocket、InetAddress、缓冲区以及DatagramPacket 都属于网络连接 

中比较麻烦的部分。最后,大家可看到run()方法实现了线程部分,使程序片能够“侦听”由服务器传回的 

响应信息。  

init()方法用大家熟悉的布局工具设置 GUI,然后创建 DatagramSocket,它将同时用于数据报的收发。  

action()方法只负责监视我们是否按下了“发送”(send)按钮。记住,我们已被限制在Java 1。0 上面,所 

以不能再用较灵活的内部类了。按钮按下以后,采取的第一项行动便是检查线程pl,看看它是否为null 

 (空)。如果不为null ,表明有一个活动线程正在运行。消息首次发出时,会启动一个新线程,用它监视来 

自服务器的回应。所以假若有个线程正在运行,就意味着这并非用户第一次发送消息。pl 句柄被设为 null, 

同时中止原来的监视者(这是最合理的一种做法,因为stop()已被Java 1。2 “反对”,这在前一章已解释过 

了)。  

无论这是否按钮被第一次按下,I2 中的文字都会清除。  

下一组语句将检查E…mail 名字是否合格。String。indexOf()方法的作用是搜索其中的非法字符。如果找到一 

个,就把情况报告给用户。注意进行所有这些工作时,都不必涉及网络通信,所以速度非常快,而且不会影 

响带宽和服务器的性能。  

名字校验通过以后,它会打包到一个数据报里,然后采用与前面那个数据报示例一样的方式发到主机地址和 

端口编号。第一个标签会发生变化,指出已成功发送出去。而且按钮上的文字也会改变,变成“重发” 

 (resend)。这时会启动线程,第二个标签则会告诉我们程序片正在等候来自服务器的回应。  

线程的run()方法会利用 NameSender 中包含的DatagramSocket 来接收数据(receive()),除非出现来自服 

务器的数据报包,否则 receive()会暂时处于“堵塞”或者“暂停”状态。结果得到的数据包会放进 

NameSender 的DatagramPacketdp 中。数据会从包中提取出来,并置入NameSender 的第二个标签。随后,线 

程的执行将中断,成为一个“死”线程。若某段时间里没有收到来自服务器的回应,用户可能变得不耐烦, 

再次按下按钮。这样做会中断当前线程(数据发出以后,会再建一个新的)。由于用一个线程来监视回应数 

据,所以用户在监视期间仍然可以自由使用UI。  

  

1。 Web页  

当然,程序片必须放到一个Web 页里。下面列出完整的 Web 页源码;稍微研究一下就可看出,我用它从自己 

开办的邮寄列表(Mailling List )里自动收集名字。  

  

  

  

  

Add Yourself to Bruce Eckel's Java Mailing List  

  

  

  

  

Add Yourself to Bruce Eckel's Java Mailing List  

  



                                                                                  559 


…………………………………………………………Page 561……………………………………………………………

The applet on this page will automatically add your email address to the mailing list; so you  

will receive update information about changes to the online version of 〃Thinking in Java;〃  

notification when the book is in print; information about uping Java seminars; and  

notification about the “Hands…on Java Seminar” Multimedia CD。 Type in your email address and  

press the button to automatically add yourself to this mailing list。   

  

  

  

If after several tries; you do not get verification it means that the Java application on the  

server is having problems。 In this case; you can add yourself to the list by sending email to   

  

Bruce@EckelObjects。  

  

  

程序片标记( )的使用非常简单,和第13章展示的那一个并没有什么区别。  



15。5。3 要注意的问题  



前面采取的似乎是一种完美的方法。没有 CGI 编程,所以在服务器启动一个 CGI 程序时不会出现延迟。数据 

报方式似乎能产生非常快的响应。此外,一旦 Java 1。1 得到绝大多数人的采纳,服务器端的那一部分就可完 

全用Java 编写(尽管利用标准输入和输出同一个非 Java 程序连接也非常容易)。  

但必须注意到一些问题。其中一个特别容易忽略:由于Java 应用在服务器上是连续运行的,而且会把大多数 

时间花在Datagram。receive()方法的等候上面,这样便为CPU 带来了额外的开销。至少,我在自己的服务器 

上便发现了这个问题。另一方面,那个服务器上不会发生其他更多的事情。而且假如我们使用一个任务更为 

繁重的服务器,启动程序用“nice ”(一个Unix 程序,用于防止进程贪吃CPU 资源)或其他等价程序即可解 

决问题。在许多情况下,都有必要留意象这样的一些应用——一个堵塞的 receive()完全可能造成CPU 的瘫 

痪。  

第二个问题涉及防火墙。可将防火墙理解成自己的本地网与因特网之间的一道墙(实际是一个专用机器或防 

火墙软件)。它监视进出因特网的所有通信,确保这些通信不违背预设的规则。  

防火墙显得多少有些保守,要求严格遵守所有规则。假如没有遵守,它们会无情地把它们拒之门外。例如, 

假设我们位于防火墙后面的一个网络中,开始用Web 浏览器同因特网连接,防火墙要求所有传输都用可以接 

受的http 端口同服务器连接,这个端口是80。现在来了这个Java 程序片NameSender,它试图将一个数据报 

传到端口8080,这是为了越过“受保护”的端口范围0…1024 而设置的。防火墙很自然地把它想象成最坏的 

情况——有人使用病毒或者非法扫描端口——根本不允许传输的继续进行。  

只要我们的客户建立的是与因特网的原始连接(比如通过典型的ISP 接驳 Internet),就不会出现此类防火 

墙问题。但也可能有一些重要的客户隐藏在防火墙后,他们便不能使用我们设计的程序。  

在学过有关 Java 的这么多东西以后,这是一件使人相当沮丧的事情,因为看来必须放弃在服务器上使用 

Java,改为学习如何编写C 或Perl 脚本程序。但请大家不要绝望。  

一个出色方案是由 Sun 公司提出的。如一切按计划进行,Web 服务器最终都装备“小服务程序”或者“服务 

程序片”(Servlet)。它们负责接收来自客户的请求(经过防火墙允许的 80 端口)。而且不再是启动一个 

CGI 程序,它们会启动小服务程序。根据Sun 的设想,这些小服务程序都是用Java 编写的,而且只能在服务 

器上运行。运行这种小程序的服务器会自动启动它们,令其对客户的请求进行处理。这意味着我们的所有程 

序都可以用 Java 写成(100%纯咖啡)。这显然是一种非常吸引人的想法:一旦习惯了 Java,就不必换用其 

他语言在服务器上处理客户请求。  

由于只能在服务器上控制请求,所以小服务程序API 没有提供 GUI 功能。这对 NameCollector。java 来说非常 

适合,它本来就不需要任何图形界面。  

在本书写作时,java。sun。 已提供了一个非常廉价的小服务程序专用服务器。Sun 鼓励其他Web 服务器开 

发者为他们的服务器软件产品加入对小服务程序的支持。  



15。6 Java 与 CGI 的沟通  



Java 程序可向一个服务器发出一个 CGI 请求,这与 HTML 表单页没什么两样。而且和HTML 页一样,这个请求 

既可以设为 GET (下载),亦可设为POST (上传)。除此以外,Java 程序还可拦截 CGI 程序的输出,所以不 



                                                                           560 


…………………………………………………………Page 562……………………………………………………………

必依赖程序来格式化一个新页,也不必在出错的时候强迫用户从一个页回转到另一个页。事实上,程序的外 

观可以做得跟以前的版本别无二致。  

代码也要简单一些,毕竟用CGI 也不是很难就能写出来(前提是真正地理解它)。所以在这一节里,我们准 

备办个CGI 编程速成班。为解决常规问题,将用C++创建一些 CGI 工具,以便我们编写一个能解决所有问题 

的CGI 程序。这样做的好处是移植能力特别强——即将看到的例子能在支持CGI 的任何系统上运行,而且不 

存在防火墙的问题。  

这个例子也阐示了如何在程序片(Applet)和CGI 程序之间建立连接,以便将其方便地改编到自己的项目 

中。  



15。6。1 CGI 数据的编码  



在这个版本中,我们将收集名字和电子函件地址,并用下述形式将其保存到文件中:  

First Last ;  

这对任何E…mail 程序来说都是一种非常方便的格式。由于只需收集两个字段,而且CGI 为字段中的编码采用 

了一种特殊的格式,所以这里没有简便的方法。如果自己动手编制一个原始的HTML 页,并加入下述代码行, 

即可正确地理解这一点:  

  

  

Name:   

Email Address:   

   

  

  

上述代码创建了两个数据输入字段(区),名为name 和 email。另外还有一个submit (提交)按钮,用于收 

集数据,并将其发给CGI 程序。Listmgr2。exe 是驻留在特殊程序目录中的一个可执行文件。在我们的Web 服 

务器上,该目录一般都叫作“cgi…bin”(注释③)。如果在那个目录里找不到该程序,结果就无法出现。填 

好这个表单,然后按下提交按钮,即可在浏览器的 URL 地址窗口里看到象下面这样的内容:  

http://myhome。/cgi…bin/Listmgr2。exe?n
返回目录 上一页 下一页 回到顶部 1 1
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!