hessian的“二进制”

最近没事,翻了翻rpc,由于在工作中接触到关于hessian和需要对hessian进行一下小小的改动,于是对其通信原理和方式进行了一下大致的研究;

 

 

什么是rpc

RPCRemote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCPUDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。RMIJ2EE中标准的RPC服务,RPC的完美封装是的将业务逻辑可以进行分布式部署,将运算密集型的工作进行分流(但请求还是同步的),在使用过程中间封装起实现可以实现在客户端调用的时候完全透明(需要在RMI客户端调用方式进行封装)

 

什么是hessian

Hessian是一个轻量级的remoting onhttp工具,使用简单的方法提供了RMI的功能. 相比WebServiceHessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。

 

 

二进制?http!

hessian的介绍过程中间,最大的亮点是二进制和httphessian分为客户端为服务端两部分,客户端根据根据借口按照invocationHandler进行代理,拦截方法请求,将URL和方法名字和参数进行序列化,采用http协议封装发送至服务端,服务端的servlet解析请求流,根据协议,凡序列化得到调用的方法和参数,生成结果,同理反馈至客户端。

下面是URLConncetion与自定义server的通信具体过程

public class UrlClient {

    public static void main(String[] args) throws Exception {

       URL url=new URL("http://127.0.0.1:8080/hwt/he");

       URLConnection conn=url.openConnection();

       conn.setAllowUserInteraction(true);

       conn.setDoOutput(true);

       conn.setDoInput(true);

       conn.setUseCaches(false);

       ((HttpURLConnection)conn).setRequestMethod("POST");

       conn.setRequestProperty("Content-type", "application/x-java-serialized-object");

       OutputStream os=conn.getOutputStream();

       os.write("hello world".getBytes());

       conn.connect();

       InputStream is=conn.getInputStream();

       while(true){

           ;

       }

    }

}

 

 

服务器

public class Server2 {

    public static void main(String[] args) {

       try {

           ServerSocket server = new ServerSocket(6061);

           while (true) {

 

              Socket request = server.accept();

              System.out.println("接受请求:");

              byte[] bs=new byte[255];

              int index=0;

              InputStream is=request.getInputStream();

              while((index=is.read(bs))>-1){

                  System.out.println(new String(bs,0,index));

              }

           }

       } catch (IOException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

 

    }

}

 

在客户端调用getInputStream()的时候,将outputStream.writebody加上配置的http header按照http协议进行了封装,发送至服务器,等待服务器回写。

Console:

接受请求:

POST / HTTP/1.1

Content-type: application/x-java-serialized-object

Cache-Control: no-cache

Pragma: no-cache

User-Agent: Java/1.6.0_10

Host: 127.0.0.1:6061

Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2

Connection: keep-alive

Content-

Length: 11

 

hello world

 

hello world被作为了http body,二进制的写入了服务器的inputStream

 

servletInputStreamRequest

我们在编写servlet的时候,能够从

    servletInputStreamRequest sis=Request.getInputStream();

中获取到,但是往往却打印不出任何数据,其实在web server(tomcat,jetty)中,并非是将监听的

         Socket socket=serverSocket.accpet();

         inputStream is=socket.getInputStream();

直接包装成为了servletInputStream,而是根据http协议进行了封装和解析。于是,我们能够成servletInputStream中获取到http body的字节数据;

 

客户端代码:

         URL url=new URL("http://127.0.0.1:8080/hwt/he");

 

服务器servlet代码:

                  System.out.println("post");

       byte[] bs=new byte[255];

       int index=0;

       InputStream is=request.getInputStream();

       while((index=is.read(bs))>-1){

           System.out.println(new String(bs,0,index));

       }

 Console:

    Hello world!

 

http是船,hessian自定义协议是人

在客户端中,根据接口进行了代理拦截,

  public Object invoke(Object proxy, Method method, Object []args)

    throws Throwable

  {

    String mangleName;

 

    synchronized (_mangleMap) {

      mangleName = _mangleMap.get(method);

    }

 

    if (mangleName == null) {

      String methodName = method.getName();

      Class<?> []params = method.getParameterTypes();

 

      // equals and hashCode are special cased

      if (methodName.equals("equals")

      && params.length == 1 && params[0].equals(Object.class)) {

    Object value = args[0];

    if (value == null || ! Proxy.isProxyClass(value.getClass()))

      return Boolean.FALSE;

 

    Object proxyHandler = Proxy.getInvocationHandler(value);

 

    if (! (proxyHandler instanceof HessianProxy))

      return Boolean.FALSE;

   

    HessianProxy handler = (HessianProxy) proxyHandler;

 

    return new Boolean(_url.equals(handler.getURL()));

      }

      else if (methodName.equals("hashCode") && params.length == 0)

    return new Integer(_url.hashCode());

      else if (methodName.equals("getHessianType"))

    return proxy.getClass().getInterfaces()[0].getName();

      else if (methodName.equals("getHessianURL"))

    return _url.toString();

      else if (methodName.equals("toString") && params.length == 0)

    return "HessianProxy[" + _url + "]";

     

      if (! _factory.isOverloadEnabled())

    mangleName = method.getName();

      else

        mangleName = mangleName(method);

 

      synchronized (_mangleMap) {

    _mangleMap.put(method, mangleName);

      }

    }

 

    InputStream is = null;

    HessianConnection conn = null;

   

    try {

      if (log.isLoggable(Level.FINER))

    log.finer("Hessian[" + _url + "] calling " + mangleName);

     

      conn = sendRequest(mangleName, args);

 

      is = conn.getInputStream();

 

      if (log.isLoggable(Level.FINEST)) {

    PrintWriter dbg = new PrintWriter(new LogWriter(log));

    HessianDebugInputStream dIs

      = new HessianDebugInputStream(is, dbg);

 

    dIs.startTop2();

   

    is = dIs;

      }

 

      AbstractHessianInput in;

 

      int code = is.read();

 

      if (code == 'H') {

    int major = is.read();

    int minor = is.read();

 

    in = _factory.getHessian2Input(is);

 

    Object value = in.readReply(method.getReturnType());

 

    return value;

      }

      else if (code == 'r') {

    int major = is.read();

    int minor = is.read();

   

    in = _factory.getHessianInput(is);

 

    in.startReplyBody();

 

    Object value = in.readObject(method.getReturnType());

 

    if (value instanceof InputStream) {

      value = new ResultInputStream(conn, is, in, (InputStream) value);

      is = null;

      conn = null;

    }

    else

      in.completeReply();

 

    return value;

      }

      else

    throw new HessianProtocolException("'" + (char) code + "' is an unknown code");

    } catch (HessianProtocolException e) {

      throw new HessianRuntimeException(e);

    } finally {

      try {

    if (is != null)

      is.close();

      } catch (Exception e) {

    log.log(Level.FINE, e.toString(), e);

      }

     

      try {

    if (conn != null)

      conn.destroy();

      } catch (Exception e) {

    log.log(Level.FINE, e.toString(), e);

      }

    }

  }

将方法名以及参数进行序列化,根据URL地址发送至服务器,这时候http body中的byte[]hessian自定义的二进制协议,这和普通的c/s二进制协议无本质区别。

servlet端,解析了servletInputStream中的http body byte[]数据,根据定制的二进制协议进行了凡序列号,根据java 发射进行了方法调用以及返回值的序列号,同理借助servletOutputStream发送至客户端(进行了response的封装,response header装饰)

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值