*:first-child {
margin-top: 0 !important; }
body > *:last-child {
margin-bottom: 0 !important; }

a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }

h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center;
text-decoration: none; }

h1 tt, h1 code {
font-size: inherit; }

h2 tt, h2 code {
font-size: inherit; }

h3 tt, h3 code {
font-size: inherit; }

h4 tt, h4 code {
font-size: inherit; }

h5 tt, h5 code {
font-size: inherit; }

h6 tt, h6 code {
font-size: inherit; }

h1 {
font-size: 28px;
color: black; }

h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }

h3 {
font-size: 18px; }

h4 {
font-size: 16px; }

h5 {
font-size: 14px; }

h6 {
color: #777777;
font-size: 14px; }

p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0; }

hr {
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0;
}

body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }

h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }

li p.first {
display: inline-block; }
li {
margin: 0; }
ul, ol {
padding-left: 30px; }

ul :first-child, ol :first-child {
margin-top: 0; }

dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }

blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }

img {
max-width: 100%; }

span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
span.float-left span {
margin: 13px 0 0; }
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }

code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }

pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }

.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }

pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre code, pre tt {
background-color: transparent;
border: none; }

sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}

kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #fcfcfc;
border: solid 1px #ccc;
border-bottom-color: #bbb;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #bbb
}

* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {

}
@media print {
table, pre {
page-break-inside: avoid;
}
pre {
word-wrap: break-word;
}
}
-->
code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}

.token.punctuation {
color: #999;
}

.namespace {
opacity: .7;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}

.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: hsla(0, 0%, 100%, .5);
}

.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}

.token.function {
color: #DD4A68;
}

.token.regex,
.token.important,
.token.variable {
color: #e90;
}

.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}

.token.entity {
cursor: help;
}
-->

HTTP协议

客户机与服务端之间的数据交互需要遵守一定的约定,比如协议版本,数据类型,是否有缓存,是否有压缩等,只有在这些约定的基础上才能相互之间愉快的工作。

Netty通信过程中的编解码

这时说的是基于TCP/IP的Netty之间的通信。TCP/IP协议下客户端与服务端之间要进行数据交互,一般需要将数据转换成二进制格式,直接传java bean是不能支持的。在RPC模式下客户端在向服务端发起请求前需要将数据做编码,服务端在接收客户端发的数据后需要做解码之后才能正常工作。

  • 解码流程

  • 编码流程

Netty 私有协议栈

为了更好的控制RPC客户端与服务端之间的通信,也可以编写私有的协议栈来支撑。

定义消息体

类似HTTP协议,包含头信息以及内容信息。


public class RpcMessage implements Serializable { private RpcMessageHeader messageHeader; private Object messageBody; }

头信息,包含内容体长度,消息类型等信息。可以根据消息类型来做不同的业务,比如区分是心跳信息还是业务或者是监控之类的信息。


public class RpcMessageHeader implements Serializable {
private int length; private int type; }

定义解码器

因为TCP/IP协议容易出现粘包拆包现象,这里为了简单直接选择继承组件提供的LengthFieldBasedFrameDecoder,只需要重写下面的方法即可:


public Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
ByteBuf frame=(ByteBuf)super.decode(ctx,in);
if(null==frame){
return null;
} RpcMessage message=new RpcMessage();
RpcMessageHeader messageHeader=new RpcMessageHeader();
messageHeader.setLength(frame.readInt());
message.setMessageHeader(messageHeader); byte[] data = new byte[message.getMessageHeader().getLength()];
frame.readBytes(data); Object obj = ProtoStuffSerializeUtil.deserialize(data, genericClass);
message.setMessageBody(obj);
return message;
}

定义编码器

编码器继承MessageToByteEncoder,将对象转换成字节的编码器


public class RpcEncoder extends MessageToByteEncoder<RpcMessage>

重点是下面的编码函数,在ByteBuf中输出数据长度以及数据体,如有其它需要可以补充其它的字段,比如消息类型。


public void encode(ChannelHandlerContext ctx, RpcMessage in, ByteBuf out) throws Exception {
if(null==in){
throw new RpcException("RpcMessage is null");
}
if (genericClass.isInstance(in.getMessageBody())) {
byte[] data = ProtoStuffSerializeUtil.serialize(in.getMessageBody());
out.writeInt(data.length);
out.writeBytes(data);
}
}

ServerHandle

  • 修改服务端执行器消息实体类型为新定义的RpcMessage

public class RpcServerInvoker extends AbstractInvoker<RpcMessage>
  • 修改服务端回调

从服务端方法获取到返回的结果后,重新封装成消息对象(RpcMessage)发送给客户端。


protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcMessage message) { this.executor.execute(new Runnable() {
@Override
public void run() {
RpcInvoker rpcInvoker=RpcServerInvoker.this.buildInvokerChain(RpcServerInvoker.this);
RpcResponse response=(RpcResponse) rpcInvoker.invoke(RpcServerInvoker.this.buildRpcInvocation((RpcRequest) message.getMessageBody()));
RpcMessage responseMessage=new RpcMessage();
byte[] data = ProtoStuffSerializeUtil.serialize(response);
RpcMessageHeader messageHeader=new RpcMessageHeader();
messageHeader.setLength(data.length);
responseMessage.setMessageHeader(messageHeader);
responseMessage.setMessageBody(response);
channelHandlerContext.writeAndFlush(responseMessage);
}
}); }

ClientHandle

  • 修改客户端执行器消息实体类型为新定义的RpcMessage

public class RpcClientInvoker extends AbstractInvoker<RpcMessage>
  • 修改客户端回调方法

接收的返回结果修改为RpcMessage,从body属性中获取原来的RpcResponse对象


public void channelRead0(ChannelHandlerContext ctx, RpcMessage message) {
RpcResponse response=(RpcResponse) message.getMessageBody();
String requestId = response.getRequestId();
ResponseFuture responseFuture = pendingRPC.get(requestId);
if (responseFuture != null) {
pendingRPC.remove(requestId);
responseFuture.done(response);
}
}
  • 修改发送请求的消息对象,组装成RpcMessage发送

public ResponseFuture invoke(RpcInvocation invocation) {
RpcRequest request=this.getRpcRequest();
ResponseFuture responseFuture = new ResponseFuture(request);
pendingRPC.put(request.getRequestId(), responseFuture);
RpcMessage message=new RpcMessage();
byte[] data = ProtoStuffSerializeUtil.serialize(request);
RpcMessageHeader messageHeader=new RpcMessageHeader();
messageHeader.setLength(data.length);
message.setMessageHeader(messageHeader);
message.setMessageBody(request);
channel.writeAndFlush(message);
return responseFuture;
}

本文源码

https://github.com/jiangmin168168/jim-framework

文中代码是依赖上述项目的,如果有不明白的可下载源码

引用

  • 文中插图来自来网络
  • 文中的思路参考了Netty权威指南

简易RPC框架-私有协议栈的更多相关文章

  1. 简易RPC框架-心跳与重连机制

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  2. 简易RPC框架-客户端限流配置

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  3. 简易RPC框架-SPI

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  4. 自行实现一个简易RPC框架

    10分钟写一个RPC框架 1.RpcFramework package com.alibaba.study.rpc.framework; import java.io.ObjectInputStrea ...

  5. 简易RPC框架-代理

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  6. 简易RPC框架-学习使用

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  7. 简易RPC框架-过滤器机制

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  8. 简易RPC框架-上下文

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  9. 简易RPC框架-熔断降级机制

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

随机推荐

  1. 更符合面向对象的数据库操作方式-OrmLite

    1. jar包下载 下载地址:http://ormlite.com/releases/,一般用core和android包即可. 如果使用的是android studio,也可以直接通过module s ...

  2. Ubuntu 14.04 安装LNMP(nginx/1.12.1+php7.1.9+mysql5.7.19)环境

    这篇教程中,我们将讨论怎样在Ubuntu 14.04搭建LNMP环境 1 安装Nginx 首先我们要更新apt源 sudo add-apt-repository ppa:nginx/stable  s ...

  3. ThreadLoacl的反思

    在我的随笔 spring mvc:注解@ModelAttribue妙用  中使用ThreadLocal来简化spring mvc控制层controller中的ModelMap,Response.Jso ...

  4. 认识大明星——轻量级容器docker知识树点亮

    docker是一个轻量级容器,属于操作系统层面的虚拟化技术,封装了文件系统(AUFS)以及网络互联,进程隔离等特性. 传统虚拟化架构: docker虚拟化架构: 可以看出,docker是没有Guest ...

  5. 把JavaScript代码改成ES6语法不完全指南

    目录 * 核心例子 * 修改成静态变量(const)或块级变量(let) * 开始修改 * 疑问解释(重复定义会发生什么) * 疑问解释(let的块级作用域是怎样的) * 疑问解释(const定义的变 ...

  6. JavaScript在应用中的技巧(二)

    ==,===运算符和强制转换 先看个表达式: "1.0e0" == { valueOf: function() { return true; } }; 是的,这个结果可能有点出乎意 ...

  7. JavaScript: 使用 atan2 来绘制 箭头 和 曲线

    最近搞Canvas绘图,知道了JavaScript中提供了atan2(y,x)这样一个三角函数.乍眼一看,不认识,毕竟在高中时,学过的三角函数有:sin,cos,arcsin,arccos,tan,a ...

  8. 【集美大学1411_助教博客】团队作业9——测试与发布(Beta版本)

    写在前面的话 已经看到了大家的发布成果,很欣喜,虽然有的团队的产品还是有一点问题,但大家也都发布成功了,这就是软件的魅力.但还是要说一些问题,大家录的视频不是没人讲解就是讲得太快,在我看来这都没有在卖 ...

  9. 团队作业4——第一次项目冲刺 SeCOnd DaY

    项目冲刺--Double Kill 喂喂喂,你好你好,听得见吗?这里是天霸动霸.tua广播站,我是主播小学生¥-¥ 第一次敏捷冲刺平稳的度过了第一天,第一天的任务大家也圆满完成啦[拍手庆祝],那么今天 ...

  10. JAVA基础第七组(5道题)

    31.题目:将一个数组逆序输出.              1.程序分析:用第一个与最后一个交换. package com.niit.homework1; /** * @author: Annie * ...