一、开发工具

1.jdk1.6 64位

百度网盘地址:https://pan.baidu.com/s/1Zwqfmi20X4ANNswZzPMzXQ 提取码:k50r

2.apache-maven-3.2.5

百度网盘地址:https://pan.baidu.com/s/1b9ZEnVclXhllmiCoVc3vyQ 提取码:x8jx

3.Eclipse IDE 4.11.0

百度网盘地址:https://pan.baidu.com/s/14_aDA2-xJpQBpDDtDZ_Sag 提取码:5abt

4.apache-tomcat-7.0.68

百度网盘地址:https://pan.baidu.com/s/1SFxj-l8rHpV4e091cT4vGw 提取码:w83x

二、远程通讯协议的基本原理

  网络通信需要做的就是将流从一台计算机传输到另外一台计算机,基于传输协议和网络 IO 来实现,其中传输协议比较出名的有 http 、 tcp 、 udp 等等, http 、 tcp 、 udp 都是在基于 Socket 概念上为某类应用场景而扩展出的传输协议,网络 IO ,主要有 bio 、 nio 、 aio 三种方式,所有的分布式应用通讯都基于这个原理而实现,只是为了应用的易用,各种语言通常都会提供一些更为贴近应用易用的应用层协议。

三、应用级协议Binary-RPC

Binary-RPC(Remote Procedure Call Protocol,远程过程调用协议)是一种和RMI(Remote Method Invocation,远程方法调用)类似的远程调用的协议,它和RMI 的不同之处在于它以标准的二进制格式来定义请求的信息 ( 请求的对象、方法、参数等 ) ,这样的好处是什么呢,就是在跨语言通讯的时候也可以使用。

  Binary -RPC 协议的一次远程通信过程:

  1 、客户端发起请求,按照 Binary -RPC 协议将请求信息进行填充;

  2 、填充完毕后将二进制格式文件转化为流,通过传输协议进行传输;

  3 、接收到在接收到流后转换为二进制格式文件,按照 Binary -RPC 协议获取请求的信息并进行处理;

  4 、处理完毕后将结果按照 Binary -RPC 协议写入二进制格式文件中并返回。

四、Hessian介绍

Hessian是一个轻量级的remoting on http工具,采用的是Binary RPC协议,所以它很适合于发送二进制数据,同时又具有防火墙穿透能力。

它基于HTTP协议传输,使用Hessian二进制序列化,对于数据包比较大的情况比较友好。但是它的参数和返回值都需要实现Serializable接口。

五、示例

1、创建服务端WebServer(Dynamic Web project)转成maven

  1)服务注解

/**
* @Title: Service.java
* @Package com.kamfu.annotation
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午11:20:28
* @version V1.0
*/
package com.kamfu.annotation; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* @ClassName: Service
* @Description:服务注解类
* @author: liandy
* @date: 2019年7月26日 下午11:20:28
*
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
String name() default ""; }

Service

  2)Class辅助类

/**
* @Title: ClassUtil.java
* @Package kamfu.util
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午10:39:29
* @version V1.0
*/
package com.kamfu.util; import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.ArrayList;
import java.util.List; import com.kamfu.annotation.Service; /**
* @ClassName: ClassUtil
* @Description:Class工具类
* @author: liandy
* @date: 2019年7月27日 上午1:32:22
*
*/
public class ClassUtil {
/**
* @Title: getAnnotationClassList
* @Description:获取指定注解的类
* @param: @param an
* @param: @param packageName
* @param: @return
* @param: @throws IOException
* @param: @throws ClassNotFoundException
* @return: List<Class<?>>
* @throws
*/
public static List<Class<?>> getAnnotationClassList(String packageName,Class annotationClass) throws IOException, ClassNotFoundException
{
List<Class<?>> result=new ArrayList<Class<?>>();
List<Class<?>> classes=scanPackage(packageName);
for(Class<?> item :classes)
{
@SuppressWarnings("unchecked")
Object ann=item.getAnnotation(annotationClass);
if(ann!=null)
{
result.add(item);
}
}
return result;
} /**
* 获取同一路径下所有子类或接口实现类
*
* @param intf
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws IOException, ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
for (Class<?> c : getClasses(cls)) {
if (cls.isAssignableFrom(c) && !cls.equals(c)) {
classes.add(c);
}
}
return classes;
}
public static List<Class<?>> getAllAssignedClass(Class<?> cls,String packageName) throws IOException, ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
for (Class<?> c : scanPackage(packageName)) {
if (cls.isAssignableFrom(c) && !cls.equals(c)) {
classes.add(c);
}
}
return classes;
} public static List<Class<?>> scanPackage(String packageName) throws IOException, ClassNotFoundException {
String path = packageName.replace('.', '/');
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URL url = classloader.getResource(path);
return getClasses(new File(url.getFile()), packageName);
} /**
* 取得当前类路径下的所有类
*
* @param cls
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public static List<Class<?>> getClasses(Class<?> cls) throws IOException, ClassNotFoundException {
String pk = cls.getPackage().getName();
String path = pk.replace('.', '/');
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
URL url = classloader.getResource(path);
return getClasses(new File(url.getFile()), pk);
} /**
* 迭代查找类
*
* @param dir
* @param pk
* @return
* @throws ClassNotFoundException
*/
private static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
if (!dir.exists()) {
return classes;
}
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
classes.addAll(getClasses(f, pk + "." + f.getName()));
}
String name = f.getName();
if (name.endsWith(".class")) {
classes.add(Class.forName(pk + "." + name.substring(0, name.length() - 6)));
}
}
return classes;
}
}

ClassUtil

  3)服务接口  

package com.kamfu.service;
/**
* @Title: IBaseService.java
* @Package
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午8:35:09
* @version V1.0
*/ /**
* @ClassName: IBaseService
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: liandy
* @date: 2019年7月26日 下午8:35:09
*
*/
public interface IBaseService {
String test();
}

IBaseService

  4)服务实现类  

/**
* @Title: BaseService.java
* @Package com.kamfu.service
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午8:36:11
* @version V1.0
*/
package com.kamfu.service; import com.kamfu.annotation.Service; /**
* @ClassName: BaseService
* @Description:TODO(这里用一句话描述这个类的作用)
* @author: liandy
* @date: 2019年7月26日 下午8:36:11
*
*/
@Service
public class BaseService implements IBaseService{ /**
* <p>Title: test</p>
* <p>Description: </p>
* @return
* @see com.kamfu.service.IBaseService#test()
*/
@Override
public String test() {
// TODO Auto-generated method stub
return "{\"a\":\"1\",\"b\":\"2\"}";
} }

BaseService

  5)自定义HessianServlet(可选)

/**
* @Title: MyHessianServlet.java
* @Package com.kamfu.service
* @Description: TODO(用一句话描述该文件做什么)
* @author: liandy
* @date: 2019年7月26日 下午10:27:15
* @version V1.0
*/
package com.kamfu.servlet; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map; import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.caucho.hessian.io.SerializerFactory;
import com.caucho.hessian.server.HessianSkeleton;
import com.caucho.services.server.ServiceContext;
import com.kamfu.annotation.Service;
import com.kamfu.util.ClassUtil; /**
* @ClassName: HessianServlet
* @Description:Servlet for serving Hessian services.
* @author: liandy
* @date: 2019年7月26日 下午10:27:15
*
*/
@SuppressWarnings("serial")
public class HessianServlet extends HttpServlet { private Map<String, Object> serviceImplCache = Collections.synchronizedMap(new HashMap<String, Object>());
private Map<String, Class<?>> serviceAPICache = Collections.synchronizedMap(new HashMap<String, Class<?>>());
private SerializerFactory _serializerFactory; public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException { // logger.debug("Hessian服务调用开始");
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getMethod().equals("POST")) {
// res.setStatus(500); // , "Hessian Requires POST");
PrintWriter out = res.getWriter(); res.setContentType("text/html");
out.println("<h1>Hessian Requires POST</h1>");
out.close(); return;
} String serviceId = req.getPathInfo();
HessianSkeleton _homeSkeleton = getHomeSkeleton(serviceId); String objectId = req.getParameter("id");
if (objectId == null)
objectId = req.getParameter("ejbid"); ServiceContext.begin(req, res, serviceId, objectId); try {
InputStream is = request.getInputStream();
OutputStream os = response.getOutputStream(); response.setContentType("x-application/hessian"); SerializerFactory serializerFactory = getSerializerFactory();
invoke(_homeSkeleton, is, os, objectId, serializerFactory); } catch (Throwable e) { throw new ServletException(e);
} finally {
ServiceContext.end();
}
// logger.debug("Hessian服务调用结束");
}
/**
* Sets the serializer factory.
*/
public void setSerializerFactory(SerializerFactory factory) {
_serializerFactory = factory;
} /**
* Gets the serializer factory.
*/
public SerializerFactory getSerializerFactory() {
if (_serializerFactory == null)
_serializerFactory = new SerializerFactory(); return _serializerFactory;
} /**
* Sets the serializer send collection java type.
*/
public void setSendCollectionType(boolean sendType) {
getSerializerFactory().setSendCollectionType(sendType);
} /**
* Sets the debugging flag.
*/
public void setDebug(boolean isDebug) {
} /**
* Sets the debugging log name.
*/
public void setLogName(String name) {
// _log = Logger.getLogger(name);
} /**
* <p>Title: init</p>
* <p>Description: 初始化</p>
* @param config
* @throws ServletException
* @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
*/
public void init(ServletConfig config) throws ServletException { super.init(config);
try { this.registerRemoteService(); if ("true".equals(getInitParameter("debug"))) {
} if ("false".equals(getInitParameter("send-collection-type")))
setSendCollectionType(false);
} catch (Throwable e) {
// TODO PAO: 此处考虑如何处理Serverlet异常
throw new ServletException(e);
}
} /**
* @Title: registerRemoteService
* @Description: 注册远端服务
* @param: @throws IOException
* @param: @throws ClassNotFoundException
* @param: @throws InstantiationException
* @param: @throws IllegalAccessException
* @return: void
* @throws
*/
private void registerRemoteService()
throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
for (Class<?> c : ClassUtil.getAnnotationClassList("com.kamfu.service", Service.class)) {
Class<?>[] interfaces = c.getInterfaces();
if (interfaces != null && interfaces.length > 0) {
this.serviceImplCache.put(c.getSimpleName(), c.newInstance());
this.serviceAPICache.put(c.getSimpleName(), interfaces[0]);
} } }
/**
* Invoke the object with the request from the input stream.
*
* @param in the Hessian input stream
* @param out the Hessian output stream
*/
protected void invoke(HessianSkeleton skeleton, InputStream is, OutputStream os, String objectId,
SerializerFactory serializerFactory) throws Exception {
skeleton.invoke(is, os, serializerFactory);
} private HessianSkeleton getHomeSkeleton(String serviceId) throws ServletException { String sId = (serviceId != null && serviceId.startsWith("/")) ? serviceId.substring(1) : serviceId;
Class<?> _homeAPI = this.getHomeAPI(sId); Object _homeImpl = this.getHomeImpl(sId);
HessianSkeleton _homeSkeleton = new HessianSkeleton(_homeImpl, _homeAPI);
return _homeSkeleton;
} private Class<?> getHomeAPI(String sId) { return this.serviceAPICache.get(sId);
} private Object getHomeImpl(String sId) { return this.serviceImplCache.get(sId);
}
}

HessianServlet

  核心代码:通过服务的实例化对象及服务的接口实例化 HessianSkeleton对象。 

  

  6)maven配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>WebServer</groupId>
<artifactId>WebServer</artifactId>
<version>0.0.1</version>
<packaging>war</packaging>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>hessian</groupId>
<artifactId>hessian</artifactId>
<version>4.0.37</version>
</dependency>
<!-- <dependency> -->
<!-- <groupId>com.kamfu.lib</groupId> -->
<!-- <artifactId>Library</artifactId> -->
<!-- <version>0.0.1</version> -->
<!-- </dependency> -->
</dependencies>
</project>

pom.xml

  7)web应用配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>WebServer</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <servlet>
<!-- 配置 HessianServlet,Servlet的名字随便配置,例如这里配置成ServiceServlet-->
<servlet-name>ServiceServlet</servlet-name>
<servlet-class>com.kamfu.servlet.HessianServlet</servlet-class> <!-- 配置接口的具体实现类 -->
<!-- <init-param> -->
<!-- <param-name>service-class</param-name> -->
<!-- <param-value>com.kamfu.service.BaseService</param-value> -->
<!-- </init-param> -->
</servlet>
<!-- 映射 HessianServlet的访问URL地址-->
<servlet-mapping>
<servlet-name>ServiceServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

web.xml

2、创建客户端Client(Java project)转成maven

  1)客户端调用

package com.kamfu.client;

import com.caucho.hessian.client.HessianProxyFactory;
import com.kamfu.service.IBaseService; /**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
try {
String url = "http://localhost:8080/WebServer/BaseService";
HessianProxyFactory factory = new HessianProxyFactory();
factory.setOverloadEnabled(true);
IBaseService basic = (IBaseService) factory.create(IBaseService.class, url);
System.out.println(basic.test());
}catch (Exception e){
e.printStackTrace();
} }
}

App

  2)maven配置  

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.kamfu.client</groupId>
<artifactId>Client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>Client</name>
<url>http://maven.apache.org</url> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>WebServer</groupId>
<artifactId>WebServer</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
</project>

pom.xml

  3)客户端从服务端接收到的数据

  

六、原理图

Hession实现远程通讯(基于Binary-RPC协议)的更多相关文章

  1. 基于二进制RPC协议法的轻量级远程调用框架 ---- Hessian

    使用Java创建Hessian服务有四个步骤: 1.创建Java接口作为公共API                             (client和server端 创建一个相同的借口) 2.使 ...

  2. 网络协议 21 - RPC 协议(中)- 基于 JSON 的 RESTful 接口协议

        上一节我们了解了基于 XML 的 SOAP 协议,SOAP 的 S 是啥意思来着?是 Simple,但是好像一点儿都不简单啊! 传输协议问题     对于 SOAP 来讲,比如我创建一个订单, ...

  3. 网络协议 20 - RPC 协议(上)- 基于XML的SOAP协议

    [前五篇]系列文章传送门: 网络协议 15 - P2P 协议:小种子大学问 网络协议 16 - DNS 协议:网络世界的地址簿 网络协议 17 - HTTPDNS:私人定制的 DNS 服务 网络协议 ...

  4. 基于Socket通讯(C#)和WebSocket协议(net)编写的两种聊天功能(文末附源码下载地址)

    今天我们来盘一盘Socket通讯和WebSocket协议在即时通讯的小应用——聊天. 理论大家估计都知道得差不多了,小编也通过查阅各种资料对理论知识进行了充电,发现好多demo似懂非懂,拷贝回来又运行 ...

  5. Java 远程通讯技术及原理分析

    在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI.MINA.ESB.Burlap.Hessian.SOAP.EJB和JMS等,这些 ...

  6. JAVA与.NET的相互调用——利用JNBridge桥接模式实现远程通讯

    分布式开发的历史 利用Remote方式调用远程对象实现服务器与客户端之间通讯是一种常用的网络开发方式,在.NET与JAVA开发当中,对Remote远程对象早已有着足够的支持(对Remote远程对象调用 ...

  7. 网络协议 22 - RPC 协议(下)- 二进制类 RPC 协议

        前面我们认识了两个常用文本类的 RPC 协议,对于陌生人之间的沟通,用 NBA.CBA 这样的缩略语,会使得协议约定非常不方便.     在讲 CDN 和 DNS 的时候,我们讲过接入层的设计 ...

  8. JAVA 远程通讯机制

    在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI.MINA.ESB. Burlap.Hessian.SOAP.EJB和JMS等,这 ...

  9. Java远程通讯技术及原理分析

    在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI.MINA.ESB.Burlap.Hessian.SOAP.EJB和JMS等,这些 ...

随机推荐

  1. Vue中子组件数据跟着父组件改变和父组件数据跟着子组件改变的方法

    一,子组件数据跟着父组件改变 父组件的代码 <template> <div class="home"> <img alt="Vue logo ...

  2. js高级编程思想

    js惰性思想: 能够执行一次就搞定绝对不会执行第二次 function createXHR(){ var xhr=null, falg=false, ary=[ function(){ return ...

  3. 波兰语 polish

    There are several systems for encoding the Polish alphabet for computers. All letters of the Polish ...

  4. java集合类笔试选择题整理含答案

    1.ArrayList list=new ArrayList(20);中的list扩充几次()A. 0B. 1C. 2D. 3答案:A分析:已经指定了长度, 所以不扩容 2.List.Set.Map哪 ...

  5. Struts2关于命名空间的例子

    佐证了这样一个原则,package存在,但action没找到,就自动去默认空间去找.如果package不存在,则自动向上一级目录找,一级级倒到根目录.  根目录再没找到,再去默认目录找 网上对于命名空 ...

  6. Django创建工程项目以及工作原理

    一.Django 创建工作项目 1.创建 North 工程项目 (1)使用CMD命令行,切换到指定路径 django-admin.py startproject north (2)使用pycharm创 ...

  7. loadRunner之参数关联

    录制脚本,对用户名和密码进行参数化: Action() { web_url("WebTours", "URL=http://127.0.0.1:1080/WebTours ...

  8. Codeforces Round #420 (Div. 2) E. Okabe and El Psy Kongroo dp+矩阵快速幂

    E. Okabe and El Psy Kongroo   Okabe likes to take walks but knows that spies from the Organization c ...

  9. UVa 699 The Falling Leaves (树水题)

    Each year, fall in the North Central region is accompanied by the brilliant colors of the leaves on ...

  10. 【Shiro】四、Apache Shiro授权

    1.授权实现方式 1.1.什么是授权 授权包含4个元素(一个比较流行通用的权限模型) Resources:资源 各种需要访问控制的资源 Permissions:权限 安全策略控制原子元素 基于资源和动 ...