在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java底层领域中有很多可实现远程通讯的技术,例如:RMI、MINA、ESB、Burlap、SOAP、EJB和JMS 等,在j2ee中,对java底层远程通讯的技术进行了封装,形成了 Hessian 、 HttpInvoker 、 XFire 、 Axis 等多种形式的远程调用技术。 但对高级程序员而言仍需要掌握Java底层领域中远程通讯的技术,尤其是rmi,xml-rpc,JMS。
1.远程服务基本原理
1)底层协议
要实现网络机器间的通讯,首先得来看看计算机系统网络通信的基本原理,在底层层面去看,网络通信需要做的就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络IO来实现,其中传输协议比较出名的有http、tcp、udp等等,http、tcp、udp都是在基于Socket概念上为某类应用场景而扩展出的传输协议,网络IO,主要有bio、nio、aio三种方式,所有的分布式应用通讯都基于这个原理而实现,只是为了应用的易用,各种语言通常都会提供一些更为贴近应用易用的应用层协议。
2)应用级协议
远程服务通讯,需要达到的目标是在一台计算机发起请求,另外一台机器在接收到请求后进行相应的处理并将结果返回给请求端,这其中又会有诸如one way request、同步请求、异步请求等等请求方式,按照网络通信原理,需要实现这个需要做的就是将请求转换成流,通过传输协议传输至远端,远端计算机在接收到请求的流后进行处理,处理完毕后将结果转化为流,并通过传输协议返回给调用端。
在java领域中知名的远程通信的应用级协议有:RMI、XML-RPC、Binary-RPC、SOAP、JMS
2.RMI
2.1RMI原理
RMI,即Java RMI(Java Remote Method Invocation),Java远程方法调用.是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。
RMI是个典型的为java定制的远程通信协议,RMI全部的宗旨就是尽可能简化远程接口对象的使用。
RMI的基础是接口,RMI构架基于一个重要的原理:定义接口和定义接口的具体实现是分开的。
来看下基于RMI的一次完整的远程通信过程的原理:
1)客户端发起请求,请求转交至RMI客户端的stub类;
2)stub类将请求的接口、方法、参数等信息进行序列化;
3)基于socket将序列化后的流传输至服务器端;
4)服务器端接收到流后转发至相应的skelton类;
5)skelton类将请求的信息反序列化后调用实际的处理类;
6)处理类处理完毕后将结果返回给skelton类;
7)Skelton类将结果序列化,通过socket将流传送给客户端的stub;
8)stub在接收到流后反序列化,将反序列化后的Java Object返回给调用者。
2.2JAVA对RMI的支持
java.rmi是JAVA提供 RMI 包。RMI是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。可以用此方法调用的任何对象必须实现该远程接口。调用这样一个对象时,其参数为 "marshalled" 并将其从本地虚拟机发送到远程虚拟机(该远程虚拟机的参数为 "unmarshalled")上。该方法终止时,将编组来自远程机的结果并将结果发送到调用方的虚拟机。如果方法调用导致抛出异常,则该异常将指示给调用方.
Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口。
2.3rmi在java中的应用
要使用RMI,必须构建四个主要的类:远程对象的本地接口、远程对象实现、RMI客户机和RMI服务器。RMI服务器生成远程对象实现的一个实例,并用一个专有的URL注册。RMI客户机在远程RMI服务器上查找服务对象,并将它转换成本地接口类型,然后像对待一个本地对象一样使用
它。
1)远程对象的本地接口
package test.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface HelloRMI extends Remote {
/**
* 简单的返回“Hello World!"字样
* @return 返回“Hello World!"字样
* @throws java.rmi.RemoteException
*/
public String helloWorld() throws RemoteException;
/**
* @param someBodyName
* @return 返回相应的问候语
* @throws java.rmi.RemoteException
*/
public String sayHelloToSomeBody(String someBodyName) throws RemoteException;
}
2)远程对象实现
package test.rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* User: staratsky
* Date: 2008-8-7 21:56:47
* 远程的接口的实现
*/
public class HelloRMIImpl extends UnicastRemoteObject implements HelloRMI {
private static final long serialVersionUID = -5464145481720553926L;
/**
* 因为UnicastRemoteObject的构造方法抛出了RemoteException异常,因此这里默认的构造方法必须写,必须声明抛出RemoteException
异常
*
* @throws RemoteException
*/
public HelloRMIImpl() throws RemoteException {
}
/**
* 简单的返回“Hello World!"字样
*
* @return 返回“Hello World!"字样
* @throws java.rmi.RemoteException
*/
public String helloWorld() throws RemoteException {
return "Hello World!";
}
/**
* @param someBodyName
* @return 返回问候语
* @throws java.rmi.RemoteException
*/
public String sayHelloToSomeBody(String someBodyName) throws RemoteException {
return "你好," + someBodyName + "!";
}
}
3)RMI服务器
package test.rmi;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
/**
* User: staratsky
* Date: 2008-8-7 22:03:35
* 创建RMI注册表,启动RMI服务,并将远程对象注册到RMI注册表中。
*/
public class HelloRMIServer {
public static void main(String args[]) {
try {
//创建一个远程对象
HelloRMI rhello = new HelloRMIImpl();
//本地主机上的远程对象注册表Registry的实例,并指定端口为8888,这一步必不可少(Java默认端口是1099),必不可缺的一
步,缺少注册表创建,则无法绑定对象到远程注册表上
LocateRegistry.createRegistry(8888);
//把远程对象注册到RMI注册服务器上,并命名为RHello
//绑定的URL标准格式为:rmi://host:port/name(其中协议名可以省略,下面两种写法都是正确的)
Naming.bind("rmi://localhost:8888/RHello", rhello);
// Naming.bind("//localhost:8888/RHello",rhello);
System.out.println(">>>>>INFO:远程IHello对象绑定成功!");
} catch (RemoteException e) {
System.out.println("创建远程对象发生异常!");
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.out.println("发生重复绑定对象异常!");
e.printStackTrace();
} catch (MalformedURLException e) {
System.out.println("发生URL畸形异常!");
e.printStackTrace();
}
}
}
4)RMI客户机
package test.rmi;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
/**
* User: staratsky
* Date: 2008-8-7 22:21:07
* 客户端测试,在客户端调用远程对象上的远程方法,并返回结果。
*/
public class HelloRMIClient {
public static void main(String args[]){
try {
//在RMI服务注册表中查找名称为RHello的对象,并调用其上的方法
HelloRMI rhello =(HelloRMI) Naming.lookup("rmi://localhost:8888/RHello");
System.out.println(rhello.helloWorld());
System.out.println(rhello.sayHelloToSomeBody("staratsky"));
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
总结:从上面的过程来看,RMI对服务器的IP地址和端口依赖很紧密,但是在开发的时候不知道将来的服务器IP和端口如何,但是客户端程序依赖这个IP和端口。
这也是RMI的局限性之一。这个问题有两种解决途径:一是通过DNS来解决,二是通过封装将IP暴露到程序代码之外。
RMI的局限性之二是RMI是Java语言的远程调用,两端的程序语言必须是Java实现,对于不同语言间的通讯可以考虑用Web Service来实现。
3.XML-RPC
3.1原理
XML-RPC 网站是这样描述的:
它是允许运行在不同操作系统、不同环境中的软件进行基于 Internet 过程调用的规范和一组实现。这种远程过程调用使用 HTTP 作为传输协议,XML 作为编码格式。XML-RPC 的定义尽可能简单,但能够传送、处理和返回复杂的数据结构。
XML-RPC消息都是HTTP-POST请求。请求的主要部分的XML。服务器端执行后的返回结果同样也是XML格式。函数调用的参数可以是scalars, numbers, strings, dates等等;也可以是混合型的记录和结构体。
所以,要完成XML-RPC,需要完成3部分工作:
1)接口实现
package test.xmlrpc;
public class HelloHandler implements ServicesHandler {
public String execute(String str){
return "Hello," + str + "!";
}
}
2)远程调用
package test.xmlrpc;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Vector;
import java.net.URL;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
public class TestClient {
public static void main(String [] args) throws Exception {
try {
// config client
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("http://localhost:8080/yizhu/HelloHandler")); // should be modified according
to your configuration of jsp container
// create a new XmlRpcClient object and bind above config object with it
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
// create parameter list
Vector<String> params = new Vector<String>();
params.addElement("MY");
// execute XML-RPC call
String result = (String) client.execute("HelloHandler.execute", params);
System.out.println(result);
} catch (MalformedURLException e) {
System.out.println(e.toString());
} catch (XmlRpcException e) {
System.out.println(e.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
3)建立一个web服务器
package test.xmlrpc;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import org.apache.xmlrpc.*;
import org.apache.xmlrpc.server.*;
import org.apache.xmlrpc.webserver.*;
public class XmlRpcServicesServlet extends HttpServlet {
private XmlRpcServletServer server;
public void init(ServletConfig pConfig) throws ServletException {
super.init(pConfig);
try {
// create a new XmlRpcServletServer object
server = new XmlRpcServletServer();
// set up handler mapping of XmlRpcServletServer object
PropertyHandlerMapping phm = new PropertyHandlerMapping();
phm.addHandler("HelloHandler", HelloHandler.class);
server.setHandlerMapping(phm);
// more config of XmlRpcServletServer object
XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl)server.getConfig();
serverConfig.setEnabledForExtensions(true);
serverConfig.setContentLengthOptional(false);
} catch (XmlRpcException e) {
try {
log("Failed to create XmlRpcServer: " + e.getMessage(), e);
} catch (Throwable ignore) {
}
throw new ServletException(e);
}
}
public void doPost(HttpServletRequest Request, HttpServletResponse Response)
throws IOException, ServletException {
server.execute(Request, Response);
}
public void doGet(HttpServletRequest Request, HttpServletResponse Response)
throws IOException, ServletException {
server.execute(Request, Response);
}
}
在web.xml中的配置
<servlet>
<servlet-name>XmlRpcServer</servlet-name>
<servlet-class>test.xmlrpc.XmlRpcServicesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>XmlRpcServer</servlet-name>
<url-pattern>/HelloHandler</url-pattern>
</servlet-mapping>
3.2RMI和RPC的区别
XML-RPC也是一种和RMI类似的远程调用的协议,它和RMI的不同之处在于它以标准的xml格式来定义请求的信息(请求的对象、方法、参数等).所以, 在RMI和RPC之间最主要的区别在于方法是如何别调用的。
在RMI中,远程接口使每个远程方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被添加到这个远程接口上,那么这个新方法就不能被RMI客户方所调用。在RPC中,当一个请求到达RPC服务器时,这个请求就包含了一个参数集和一个文本值,通常形成“classname.methodname”的形式。这就向RPC服务器表明,被请求的方法在为“classname”的类中,名叫“methodname”。然后RPC服务器就去搜索与之相匹配的类和方法,并把它作为那种方法参数类型的输入。这里的参数类型是与RPC请求中的类型是匹配的。一旦匹配成功,这个方法就被调用了,其结果被编码后返回客户方。
3.3xml-rpc的缺点
1)XML-RPC的消息系统过于简单,没有完整意义上的消息模型
2)XML-RPC调用服务的方式要求直接指定对象和方法,称不上完整的面向服务的体系
3)XML-RPC服务器端提供的服务实际上是特定对象的某个方法,限制了服务器端的开发
4.Binary-RPC
Binary-RPC看名字就知道和XML-RPC是差不多的了,不同之处仅在于传输的标准格式由XML转为了二进制的格式。
Hessian是由caucho提供的一个基于binary-RPC实现的远程通讯library。
1)写一个接口:
package test.hassian;
public interface SayHello {
public String sayHello(String name);
public Student getStudent();
}
2)编写一个实现:
package test.hassian;
import com.caucho.hessian.server.HessianServlet;
public class SayHelloImpl extends HessianServlet implements SayHello {
public String sayHello(String name) {
return "hello "+name;
}
public Student getStudent(){
Student s=new Student();
s.setName("staratsky");
s.setSchool("ustc");
return s;
}
}
3)bean类
package test.hassian;
import java.io.Serializable;
public class Student implements Serializable {
/**
*
*/
private static final long serialVersionUID = -9006571629757493042L;
private String name;
private String school;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String toString() {
return name+" "+school;
}
}
4)远程调用类
package test.hassian;
import java.net.MalformedURLException;
import com.caucho.hessian.client.HessianProxyFactory;
public class HessianClientTest {
public static void main(String[] args) {
String url="http://127.0.0.1:8080/yizhu/hassiantest";
HessianProxyFactory factory=new HessianProxyFactory();
try {
SayHello say=(SayHello) factory.create(SayHello.class, url);
System.out.println(say.sayHello("abc"));
System.out.println(say.getStudent());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
服务器端的配置
在web.xml中,加入下面两段代码:
<servlet>
<servlet-name>hassiantest</servlet-name>
<servlet-class>
test.hassian.SayHelloImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hassiantest</servlet-name>
<url-pattern>/hassiantest</url-pattern>
</servlet-mapping>
5.JMS
JMS呢,是实现java领域远程通信的一种手段和方法,基于JMS实现远程通信时和RPC是不同的,虽然可以做到RPC的效果,但因为不是从协议级别定义的,因此我们不认为JMS是个RPC协议,但它确实是个远程通信协议,在其他的语言体系中也存在着类似JMS的东西,可以统一的将这类机制称为消息机制,而消息机制呢,通常是高并发、分布式领域推荐的一种通信机制,这里的主要一个问题是容错。
来看JMS中的一次远程通信的过程:
客户端将请求转化为符合JMS规定的Message;
通过JMS API将Message放入JMS Queue或Topic中;
如为JMS Queue,则发送中相应的目标Queue中,如为Topic,则发送给订阅了此Topic的JMS Queue。
处理端则通过轮训JMS Queue,来获取消息,接收到消息后根据JMS协议来解析Message并处理。
详看<实战activeMQ(http://staratsky.iteye.com/blog/275045) >
分享到:
相关推荐
Java远程通讯技术是分布式服务框架中的关键组成部分,它允许不同机器上的应用程序相互通信,实现服务的远程调用。在Java领域,有多种技术可以实现远程通讯,包括RMI(Remote Method Invocation)、XML-RPC、SOAP、...
通过阅读和理解这些代码,开发者可以深入学习Java远程控制的实现细节。 总的来说,Java实现远程控制技术是一项涉及网络编程、多线程处理、图形处理以及安全性的综合任务。提供的源代码是学习和实践这一技术的宝贵...
这份“Java远程通讯技术及原理分析共18页.pdf”文档很可能是深入探讨了Java在分布式系统中的通信机制,包括其核心概念、技术和实践应用。 首先,我们要理解什么是Java远程通讯(Java Remote Method Invocation,...
这篇名为“Java远程控制简单实现”的博客文章可能探讨了如何利用Java技术实现远程控制系统。远程控制通常涉及通过网络对远程计算机进行操作,这在系统管理、自动化任务执行以及分布式系统通信中非常常见。 首先,...
下面我们将详细探讨如何使用Java来构建一个简单的远程监控系统。 首先,我们要理解JMX。JMX是一种标准,用于管理和监控Java应用程序。通过创建MBeans(Managed Beans),我们可以封装应用中的特定功能或资源,并...
Java 远程控制技术是利用 Java 的网络编程能力来实现在不同计算机间进行交互操作的一种技术。在 Java 中,远程控制通常涉及到 RMI (Remote Method Invocation)、JMX (Java Management Extensions) 和 SSH (Secure ...
总结,Java远程桌面连接技术利用Java RMI或JDTS实现,提供了跨平台的远程桌面访问能力。在开发过程中,需要注意安全性、性能优化和用户体验。通过理解并掌握这些知识点,开发者可以构建高效、安全的远程桌面解决方案...
首先,我们要理解Java远程方法调用(Java RMI,Remote Method Invocation)是实现远程协助的基础。RMI允许一个Java对象调用另一个在不同JVM(Java Virtual Machine)上的对象的方法,仿佛它们都在同一个程序中。因此...
总的来说,Java远程控制程序通过Java RMI技术实现了跨越网络的通信,它在分布式系统中有广泛的应用,例如远程监控、系统管理、自动化任务调度等。通过深入学习和实践,你可以掌握这种强大的工具,提升你的IT技能。
Java RMI(Remote Method Invocation,远程方法调用)是Java平台提供的一种用于分布式计算的技术,它允许一个Java对象调用另一个在不同JVM上的对象的方法。这个简单的例子将引导我们了解如何利用Java RMI实现远程...
RMI基于JRMP(Java Remote Messaging Protocol)协议进行通信,这是一种专门为Java远程对象设计的协议,确保了跨平台的兼容性,只要目标系统支持JRE(Java Runtime Environment),RMI应用就能在其中正常运行。...
在这个场景下,我们将探讨如何使用Java编程语言来实现一个简单的远程协助应用。Java的Socket编程是实现这种功能的基础,因为Socket提供了客户端和服务器之间的双向通信。 首先,我们需要理解Java Socket的工作原理...
本篇文章将探讨如何使用Java来实现简单的分布式系统,并进行远程方法调用。 首先,分布式系统是由多个独立的节点(计算机或进程)组成的网络,这些节点通过通信和协作来完成共同的任务。在Java中,我们可以利用Java...
【Java远程通信技术——Axis实战】 在互联网时代,网络通信技术是软件开发不可或缺的一部分。TCP/IP和UDP/IP作为底层传输协议,承载了大部分网络数据,而HTTP协议则在此基础上提供了超文本传输。Java中,有多种远程...
"java远程通信及应用的研究"部分可能深入探讨了RMI的原理、最佳实践以及在实际项目中的应用案例。"Java源码.zip"则可能包含了相关的示例代码,帮助读者更好地理解和学习Java网络通信技术。 总的来说,Java在网络...
总的来说,用Java实现基于SOAP的XML文档网络传输和RPC涉及到多个技术层面,包括XML解析、网络通信、对象序列化和反序列化等。通过理解这些概念和技术,开发者可以构建高效、可靠且跨平台的Web服务。
本文将深入探讨这一主题,详细介绍如何利用Java技术设计并实现一个网络远程监控系统。 【描述】: Java作为一种广泛使用的编程语言,其强大的网络功能和丰富的类库为构建网络远程监控系统提供了坚实的基础。网络...
Java RMI(Remote Method Invocation,远程方法调用)是Java平台提供的一种用于在不同网络节点上的Java对象之间进行通信的技术。这个技术允许一个Java对象在一台机器上执行方法,而这个方法的实现实际上位于另一台...