免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1323 | 回复: 1
打印 上一主题 下一主题

Applet与Servlet通讯的四种方法及其比较(ZT出处不详) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-08-11 03:06 |只看该作者 |倒序浏览
Applet与Servlet之间的联系一般是间接的,即页面请求由浏览器发送给Servlet,作为回答,Servlet将结果生成HTML文档发送给浏览器。很多时候在Servlet与Applet之间建立直接的联系是没有必要的,但如果要显示一些实时的动态数据,如聊天室窗口、新闻显示、股市行情等,建立两者之间的直接联系就很有用了。特别地,在较为复杂的分布式Java应用中,这种通讯更是必不可少。在客户端Java程序与服务器端Java程序之间建立这种复杂的交互方式仅仅使用Servlet与Applet API是不够的,本文为你介绍和比较四种通讯方式:通过HTML页面传递参数,用java.net包的网络功能建立直接网络连接,远程方法调用(RMI)与CORBA。
   一、通过HTML页面传递Applet参数

   通过HTML页面传递参数是在Servlet与Applet之间建立联系最为常用的方法。Servlet只要把传递给Applet的参数写入HTML页面就可以了。这种通讯是单向的,用于实现Servlet对Applet的控制。其实现方法类如:


  1. // doGet()方法生成一个包含Applet的HTML页面,
  2. // 该Applet需要一个Data参数

  3. public void doGet(HttpServletRequest request,HttpServletResponse response)
  4. throws ServletException, IOException {
  5.    response.setContentType("text/html");
  6.    PrintWriter out = new PrintWriter ( response.getOutputStream());
  7.    out.write("<  HTML>;<  HEAD>;<  TITLE>; HTML Example<  /TITLE>; <  /HEAD>;<  BODY>;");
  8.    out.write("Servlet通过PARAM标记传递参数给Applet. ");
  9.    out.write("<  APPLET code=\"SimpleApplet\" width=\"225\" height=\"149\">;");
  10.    // 写入PARAM标记
  11.    out.write("<  param name=\"Data\" value=\"");
  12.    out.write(java.text.DateFormat.getDateInstance().format(new java.util.Date()));
  13.    out.write("\">;<  /APPLET>;<  /BODY>;<  /HTML>;");
  14.    out.close();
  15. }
复制代码


   这种方法很简单,但它有两个缺点。首先,所有参数都是静态的,即一旦HTML页面发送完成,要更新其中部分数据就很困难了。虽然可以使用HTTP的刷新机制,但这种刷新需要重新下载整个页面,效率是很低的。第二,如果需要传递给Applet的数据量很大或数据结构很复杂,就会使得HTML页面过于庞大或复杂了。

   二、用java.net包建立双向通讯

   第二种方法是利用java.net包提供的网络能力。以有连接流通讯方式为例,在服务器端的操作为一般为:

   ⑴ 创建一个ServerSocket对象,在指定端口监听客户端发来的请求。

   ⑵ 在接收到请求时accept()方法将返回一个Socket对象。

   ⑶ 用上述Socket对象创建输入、输出流对象。

   ⑷ 通过输入、输出流与客户交互。

   ⑸ 交互完毕,关闭输入、输出流与Socket。

   ⑹ 服务程序运行结束,关闭ServerSocket。

   实现代码代码类如:


  1. try{
  2.    boolean flag=true;
  3.    Socket clientSocket=null;

  4.    ServerSocket serverSocket = new ServerSocket(0);
  5.    System.out. println("Server listen on: " +serverSocket.getLocalPort());
  6.    while(flag){
  7.       clientSocket=serverSocket.accept();
  8.       DataInputStream is=new DataInputStream( new bufferedInputStream(clientSocket.getInputStream()));
  9.       PrintStream os=new PrintStream( new bufferedOutputStream(clientSocket.getOutputStream()));
  10.       // 处理Applet请求
  11.      os.close();
  12.       is.close();
  13.       clientSocket.close();
  14.    }
  15.    serverSocket.close();
  16. }catch( IOException e){
  17.    System.err. println(" Exception: "+e);
  18. }
复制代码


   在客户端的操作为:

   ⑴ 创建Socket对象建立与服务器的连接。

   ⑵ 用该Socket对象创建输入、输出流。

   ⑶ 与服务器交互。

   ⑷ 交互完毕,关闭输入、输出流与Socket。

   实现代码类如:

  1. try {
  2.    Socket clientSocket =new Socket("serverName",7);
  3.    OutputStream os=clientSocket.getOutputStream();
  4.    DataInputStream is=new DataInputStream( clientSocket.getInputStream());
  5.    // 其它操作.
  6.    os.close();
  7.    is.close();
  8.    clientSocket.close();
  9. }catch(Exception e){
  10.    System.err. println("Exception:"+e);
  11. }
复制代码

   这种方法只依赖于标准的Java网络支持,不需要用到附加的软件包或工具, 因此显得相当简洁和灵活,易于实现某些特殊的需要。但在另一方面,服务器端对进入请求以及客户端对返回结果的分析工作量较大。如果服务器端要执行大量的操作,可以考虑使用RMI。

   三、远程方法调用RMI

   Java的RMI技术显著地改善了客户程序操作复杂的服务器端对象的能力。对Applet来说,服务器端对象所提供的远程方法可以象普通的客户端句柄一样调用。使用RMI时应先定义远程接口,即一个继承自java.rmi.Remote的公用接口。在该接口中定义要求在服务器上运行的方法,所有这些方法的throws子句至少应该声明java.rmi.RemoteException异常。

   接下来是实现远程接口,远程接口的实现类应该:

   ⑴ 指定所实现的一个或多个接口。

   ⑵ 定义远程对象的构造方法。

   ⑶ 提供所有可供远程调用的方法的实现。

   ⑷ 创建和安装安全管理器。

   ⑸ 创建一个或多个远程对象实例。

   ⑹ 注册至少一个远程对象。

   下面的代码实现一个返回日期字符串的getData()远程方法,该方法由接口RMIServ2App定义:


  1. // 本类继承自UnicastRemoteObject,实现接口serv2app

  2. package com.servletsolutions.serv2app.rmi;

  3. import java.rmi.*;
  4. import java.rmi.server.*;

  5. public class RMIImplementation extends UnicastRemoteObject
  6. implements RMIServ2App{
  7.    public RMIImplementation() throws RemoteException{}
  8.    public String getData() throws RemoteException{
  9.       return java.text.DateFormat.getDateInstance().format(new java.util.Date());
  10.    }

  11.    public static void main(String[] args){
  12.        // 安全管理器
  13.       System.setSecurityManager(new RMISecurityManager());
  14.       try{
  15.       // 远程对象实例
  16.       RMIImplementation bootStrap = new RMIImplementation();
  17.       // 注册
  18.       Naming.bind(args[0], bootStrap);
  19.          System.out. println(args[0] + " 注册成功");
  20.       }catch(Exception e){
  21.          System.err. println("注册失败.");
  22.          System.err. println(e);
  23.       }
  24.    }
  25. }
复制代码

   在客户端,Applet对接口RMIServ2App的引用通过调用Naming.lookup(String)获得,如下所示:


  1.    RMIServ2App obj = (RMIServ2App)Naming.lookup("//" + getCodeBase().getHost() + "/ServerName");
复制代码


   除了编译Java代码之外,还要用rmic编译器生成远程对象的存根和骨架。存根(Stub)是远程对象在客户端的代理,它将RMI调用传递给服务器端的骨架(Skeleton),后者负责将该调用传递给实际的远程方法。例如执行命令rmic com.servletsolutions.RMIImplementation,则生成的两个类文件分别为RMIImplementation_Stub.class 和RMIImplementation_Stub.class,前者封装入Applet且运行于客户端,后者封装入Servlet且运行与服务器端。

   当大量的数据是由服务器端的对象动态提供时使用RMI是非常合适的。虽然RMI支持面向对象的分布式编程,但它要求客户端和服务器端都是Java程序。因此,对于使用混合语言开发的应用来说,CORBA比RMI更为适用。

   四、使用CORBA

   CORBA即公用对象请求代理体系(Common Object Request Broker Architecture),它的使用方法类似于RMI:定义接口,使用某个工具创建Stub和Skeleton,实现接口,在服务器上注册后客户就可以像本地对象一样访问远程对象了。两者主要的不同之处在于,CORBA使用一种语言中立的接口定义语言(IDL)来定义接口,IDL是一种可用于混合语言环境的更为广泛的协议集。CORBA最大的缺点在于客户本身必须具备调用ORB的能力,这往往意味着增加一个体积较大的JAR文件。

   下面的CORBAServ2App.idl是上述getData()接口的IDL描述,它定义了一组与Java包名字对应的嵌套模块:


  1. module com {
  2.    module servletsolutions {
  3.       module serv2app {
  4.          module corba {
  5.             interface CORBAServ2App{
  6.                string getData();
  7.             };
  8.          };
  9.       };
  10.    };
  11. };
复制代码

   可以用idl2java从IDL文件生成对应的java文件。其中_CORBAServ2AppImplBase.java包含了描述该接口的java抽象类,下面的CORBAImplementation类继承自抽象类_CORBAServ2AppImplBase并具体实现getData()方法:


  1. package com.servletsolutions.serv2app.corba;

  2. public class CORBAImplementation extends _CORBAServ2AppImplBase {
  3.    CORBAImplementation(String s){
  4.       super(s);
  5.    }

  6.    public String getData(){
  7.       return java.text.DateFormat.getDateInstance().format(new java.util.Date());
  8.    }
  9. }
复制代码

   为了让该类可以被客户访问,Servlet中还应该创建其实例。代码如下所示:


  1. // 在Servlet的init()方法中初始化CORBAImplementation对象
  2. // 其中BOA(Basic Object Adapter)的作用类似于RMI中的注册服务

  3. public class CORBAServlet extends HttpServlet{
  4.    String CORBAName;

  5.    public void init(
  6.    ServletConfig config) throws ServletException {
  7.       super.init(config);
  8.       try {
  9.          CORBAName = getInitParameter("CORBAName");
  10.          org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init();
  11.          org.omg.CORBA.BOA boa = orb.BOA_init();
  12.          com.servletsolutions.serv2app.corba.CORBAServ2App implObject = new CORBAImplementation(CORBAName);
  13.          boa.obj_is_ready(implObject);
  14.          boa.impl_is_ready();
  15.       }
  16.       catch (Exception e) {
  17.          e.printStackTrace();
  18.       }
  19.    }
  20. }
复制代码

   IDL2Java同时为客户端生成CORBAServ2AppHelper类,Applet通过该类与服务器交互。Stub与Skeletion的作用类似于它们在RMI中,不同之处在于本地ORB接口负责所有与远程ORB之间的连接。

   如果服务器端的数据计算量非常大(比如数据库操作),或在未知客户端应用程序的情况下需要从服务器端引出大量的功能,RMI和CORBA较为合适。考虑到已有大量可用的ORB以及CORBA规范的成熟,在大多数情况下CORBA更为可取。但如果希望减小客户端的复杂程度,则RMI是最好的方法。

论坛徽章:
0
2 [报告]
发表于 2003-08-11 03:13 |只看该作者

Applet与Servlet通讯的四种方法及其比较(ZT出处不详)

看java版人气不足(当然是跟清茶比),继续过来捧场。
正准备学j2ee, 请老大们多指教。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP