applet与servlet之间的联系一般是间接的,即页面请求由浏览器发送给servlet,
作为回答,servlet将结果生成html文档发送给浏览器。很多时候在servlet与applet之
间建立直接的联系是没有必要的,但如果要显示一些实时的动态数据,如聊天室窗口、
新闻显示、股市行情等,建立两者之间的直接联系就很有用了。特别地,在较为复杂的
分布式java应用中,这种通讯更是必不可少。在客户端java程序与服务器端java程序之
间建立这种复杂的交互方式仅仅使用servlet与applet api是不够的,本文为你介绍和比
较四种通讯方式:通过html页面传递参数,用java.net包的网络功能建立直接网络连接
,远程方法调用(rmi)与corba。
一、通过html页面传递applet参数
通过html页面传递参数是在servlet与applet之间建立联系最为常用的方法。serv
let只要把传递给applet的参数写入html页面就可以了。这种通讯是单向的,用于实现s
ervlet对applet的控制。其实现方法类如:
// doget()方法生成一个包含applet的html页面,
// 该applet需要一个data参数
这种方法很简单,但它有两个缺点。首先,所有参数都是静态的,即一旦html页面
发送完成,要更新其中部分数据就很困难了。虽然可以使用http的刷新机制,但这种刷
新需要重新下载整个页面,效率是很低的。第二,如果需要传递给applet的数据量很大
或数据结构很复杂,就会使得html页面过于庞大或复杂了。
二、用java.net包建立双向通讯
第二种方法是利用java.net包提供的网络能力。以有连接流通讯方式为例,在服务
器端的操作为一般为:
⑴ 创建一个serversocket对象,在指定端口监听客户端发来的请求。
⑵ 在接收到请求时accept()方法将返回一个socket对象。
⑶ 用上述socket对象创建输入、输出流对象。
⑷ 通过输入、输出流与客户交互。
⑸ 交互完毕,关闭输入、输出流与socket。
⑹ 服务程序运行结束,关闭serversocket。
实现代码代码类如:
try{
boolean flag=true;
socket clientsocket=null;
serversocket serversocket = new serversocket(0);
system.out.println("server listen on: " +serversocket.getlocalport());
while(flag){
clientsocket=serversocket.accept();
datainputstream is=new datainputstream( new bufferedinputstream(clientsocket
.getinputstream()));
printstream os=new printstream( new bufferedoutputstream(clientsocket.getout
putstream()));
// 处理applet请求
os.close();
is.close();
clientsocket.close();
}
serversocket.close();
}catch( ioexception e){
system.err.println(" exception: "+e);
}
在客户端的操作为:
⑴ 创建socket对象建立与服务器的连接。
⑵ 用该socket对象创建输入、输出流。
⑶ 与服务器交互。
⑷ 交互完毕,关闭输入、输出流与socket。
实现代码类如:
try {
socket clientsocket =new socket("servername",7);
outputstream os=clientsocket.getoutputstream();
datainputstream is=new datainputstream( clientsocket.getinputstream());
// 其它操作.
os.close();
is.close();
clientsocket.close();
}catch(exception e){
system.err.println("exception:"+e);
}
这种方法只依赖于标准的java网络支持,不需要用到附加的软件包或工具, 因此
显得相当简洁和灵活,易于实现某些特殊的需要。但在另一方面,服务器端对进入请求
以及客户端对返回结果的分析工作量较大。如果服务器端要执行大量的操作,可以考虑
使用rmi。
三、远程方法调用rmi
java的rmi技术显著地改善了客户程序操作复杂的服务器端对象的能力。对applet
来说,服务器端对象所提供的远程方法可以象普通的客户端句柄一样调用。使用rmi时应
先定义远程接口,即一个继承自java.rmi.remote的公用接口。在该接口中定义要求在服
务器上运行的方法,所有这些方法的throws子句至少应该声明java.rmi.remoteexcepti
on异常。
接下来是实现远程接口,远程接口的实现类应该:
⑴ 指定所实现的一个或多个接口。
⑵ 定义远程对象的构造方法。
⑶ 提供所有可供远程调用的方法的实现。
⑷ 创建和安装安全管理器。
⑸ 创建一个或多个远程对象实例。
⑹ 注册至少一个远程对象。
下面的代码实现一个返回日期字符串的getdata()远程方法,该方法由接口rmiser
v2app定义:
// 本类继承自unicastremoteobject,实现接口serv2app
package com.servletsolutions.serv2app.rmi;
import java.rmi.*;
import java.rmi.server.*;
public class rmiimplementation extends unicastremoteobject
implements rmiserv2app{
public rmiimplementation() throws remoteexception{}
public string getdata() throws remoteexception{
return java.text.dateformat.getdateinstance().format(
new java.util.date());
}
public static void main(string[] args){
// 安全管理器
system.setsecuritymanager(new rmisecuritymanager());
try{
// 远程对象实例
rmiimplementation bootstrap = new rmiimplementation();
// 注册
naming.bind(args[0], bootstrap);
system.out.println(args[0] + " 注册成功");
}catch(exception e){
system.err.println("注册失败.");
system.err.println(e);
}
}
}
在客户端,applet对接口rmiserv2app的引用通过调用naming.lookup(string)获得
,如下所示:
rmiserv2app obj = (rmiserv2app)naming.lookup("//" + getcodebase().getho
st() + "/servername");
除了编译java代码之外,还要用rmic编译器生成远程对象的存根和骨架。存根(s
tub)是远程对象在客户端的代理,它将rmi调用传递给服务器端的骨架(skeleton),
后者负责将该调用传递给实际的远程方法。例如执行命令rmic com.servletsolutions.
rmiimplementation,则生成的两个类文件分别为rmiimplementation_stub.class 和rm
iimplementation_stub.class,前者封装入applet且运行于客户端,后者封装入servle
t且运行与服务器端。
当大量的数据是由服务器端的对象动态提供时使用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
包名字对应的嵌套模块:
module com {
module servletsolutions {
module serv2app {
module corba {
interface corbaserv2app{
string getdata();
};
};
};
};
};
可以用idl2java从idl文件生成对应的java文件。其中_corbaserv2appimplbase.j
ava包含了描述该接口的java抽象类,下面的corbaimplementation类继承自抽象类_cor
baserv2appimplbase并具体实现getdata()方法:
package com.servletsolutions.serv2app.corba;
public class corbaimplementation extends _corbaserv2appimplbase {
corbaimplementation(string s){ super(s); }
public string getdata(){
return java.text.dateformat.getdateinstance().format(new java.util.date());
}
}
为了让该类可以被客户访问,servlet中还应该创建其实例。代码如下所示:
// 在servlet的init()方法中初始化corbaimplementation对象
// 其中boa(basic object adapter)的作用类似于rmi中的注册服务
(程序略)
闽公网安备 35060202000074号