1. 前言

前面已经分析了Dubbo是如何暴露以及引用远程服务的,接下来自然是服务调用的实现细节了,但是在那之前,有必要先了解Dubbo的网络通信协议。

在单机系统中,调用本地方法获取结果很简单,因为同一个进程里内存是共享的。但是在分布式系统中,远程方法调用就显得较为复杂,必须通过网络将内存中的数据传输给对方,数据以何种格式传输呢?这就需要双方约定一个协议。

2. 通讯协议细节


这是Dubbo官方文档给的图,可以看出协议主要分为两块:16字节定长的Header、变长的Body。

2.1 协议头和协议体

Dubbo通讯协议头Header由16字节组成,Header设计的非常紧凑,能用bit表示就绝不用byte,内容如下:

Bit 字段 说明
0~15 Magic Number 魔数,固定0xdabb
16 Req/Res 0=Response,1=Request
17 2Way 仅在Request在有用。是否期望服务器返回数据
18 Event 是否事件信息,如心跳
19~23 Serialization ID 序列化类型ID
24~31 Status 响应状态
32~95 Request ID 请求唯一标识
96~127 Data Length Body的长度
变长部分 Body 对象序列化的byte[]

Body部分是变长的,长度DataLength已经写在Header里了。Dubbo可以根据DataLength解决TCP粘包/拆包的问题,如果读取的字节数不足16,说明连一个完整的Header都没有接收到,此时会等待对端发送更多的数据。读取到一个完整的Header,会解析出DataLength,然后判断Body是否完整,不完整同样会等待对端传输更多的数据,完整则解析Body进行后续的请求处理。

2.2 编解码和序列化

Dubbo对于请求用Request类描述,对于响应用Response描述。
Dubbo针对协议头Header部分,使用Codec编解码,针对Body部分,使用序列化的方式。

当Consumer向Provider发起RPC调用时,会先创建RpcInvocation对象,再创建Request对象。然后利用NettyClient将数据发送到对端。我们知道,网络传输的总是字节序列,所以Request对象会经过编码再发送,对应的方法是ExchangeCodec#encodeRequest(),Dubbo会根据协议的格式向Channel先写入Header,再写入Body。

protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException {// 序列化策略 默认hessian2Serialization serialization = getSerialization(channel);// 协议头Header 16字节byte[] header = new byte[HEADER_LENGTH];// 2字节 魔数Bytes.short2bytes(MAGIC, header);header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId());if (req.isTwoWay()) {header[2] |= FLAG_TWOWAY;}if (req.isEvent()) {header[2] |= FLAG_EVENT;}// RequestId 全局自增Bytes.long2bytes(req.getId(), header, 4);int savedWriteIndex = buffer.writerIndex();buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);// 序列化DataChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);ObjectOutput out = serialization.serialize(channel.getUrl(), bos);if (req.isEvent()) {encodeEventData(channel, out, req.getData());} else {encodeRequestData(channel, out, req.getData(), req.getVersion());}out.flushBuffer();if (out instanceof Cleanable) {((Cleanable) out).cleanup();}bos.flush();bos.close();int len = bos.writtenBytes();// 校验负载,Body是否太大checkPayload(channel, len);Bytes.int2bytes(len, header, 12);buffer.writerIndex(savedWriteIndex);buffer.writeBytes(header); // write header.buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
}

Provider响应的Response,也是需要编码再发送的,处理流程和Request差不多,这里就不贴代码了。

对于Body部分,RpcInvocation该如何编码呢?我们以DubboCodec为例,事实上Dubbo并不会将整个RpcInvocation对象序列化输出,而是按照固定的格式,将重要信息写入到ObjectOutput。
格式如下:

  1. 协议Version
  2. ServiceName
  3. ServiceVersion
  4. MethodName
  5. ParameterTypesDesc
  6. Arguments序列化
  7. Attachments序列化

Provider按照约定的格式,依次将这些数据再读取出来即可。

protected void encodeRequestData(Channel channel, ObjectOutput out, Object data, String version) throws IOException {RpcInvocation inv = (RpcInvocation) data;out.writeUTF(version);String serviceName = inv.getAttachment(INTERFACE_KEY);if (serviceName == null) {serviceName = inv.getAttachment(PATH_KEY);}out.writeUTF(serviceName);out.writeUTF(inv.getAttachment(VERSION_KEY));out.writeUTF(inv.getMethodName());out.writeUTF(inv.getParameterTypesDesc());Object[] args = inv.getArguments();if (args != null) {for (int i = 0; i < args.length; i++) {out.writeObject(encodeInvocationArgument(channel, inv, i));}}out.writeAttachments(inv.getObjectAttachments());
}

3. 总结

Dubbo通讯协议分为Header和Body两部分,Header固定由16个字节组成,设计的非常紧凑,尽可能的用bit表示,包含:魔数、请求响应标识、2Way标识、Event标识、序列化ID、Status、RequestID、DataLength。Body则是变长的,长度记录在Header最后4字节里,Dubbo可以基于此来解决TCP的粘包/拆包问题。
Header部分采用Codec编解码,Body部分使用序列化,具体取决于使用的的序列化实现方案,默认是Hessian2。

Dubbo网络通讯协议相关推荐

  1. 网络编程2_网络通讯协议, socket(tcp, udp)

    一. 网络通讯协议     互联网协议的功能: 定义计算机如何接入internet, 以及接入internet的计算机的通信标准     互联网协议按照功能的不同分为osi七层或tcp/ip五层    ...

  2. 企业即时通讯软件,网络通讯协议和机制怎么选?

    一个大型组织如果需要从头开发一套自主可控的即时通讯软件,从技术角度第一个要考虑的核心问题就是:如何确定客户端和服务器之间的通讯协议和通讯机制? 通讯协议怎么选? 大型组织架构就意味着员工人数多,网络情 ...

  3. TCP/IP 中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议

    原文地址:http://hi.baidu.com/albyuyrgqgbbhoq/item/65006d2d002ab33195f62ba1 TCP/IP(Transmission Control P ...

  4. 如何通过序列化在网络间传递对象,网络协议:轻松定义自己的网络通讯协议

    //每次编写设计网络通讯程序时,总面对一个问题,就是要自定义一组应用协议(即通讯协议),然后再写相应的方法来解析协议,并提供相应的接口供上层调用.假如只是简单的文本信息通讯还轻易,但要交换一些控制信息 ...

  5. html网络通信协议设计,智能家居无线网络通讯协议设计方案

    "智能家居"(smart home)又称智能住宅,它利用先进的计算机技术.嵌入式系统技术.网络通讯技术与传感器技术等,把家中的各种设备有机的结合起来,优化用户生活方式,方便用户管理 ...

  6. 通讯协议,网络通讯协议基本原理透析

    文章目录 通讯协议 TCP/IP协议 TCP/IP模型 osi版 基本版 应用层 传输层 网络层 数据链层 物理层 通讯协议 我们想要进⾏数据通讯分⼏步? 1.找到对⽅ip 2 .数据要发送到对⽅指定 ...

  7. 游戏开发中网络通讯协议对比

    在网络游戏开发中,通讯协议是一个无法被避免的问题,无论对于客户端开发中还是服务器开发程序猿而言,制定一个合适的通讯协议是很有必要的 游戏联网需求有弱联网游戏,即时互动类游戏 选择通讯协议的时候主要关注 ...

  8. 几种网络通讯协议(WIFI,WAPI,GSM,GPRS,CDMA)概述

    什么是WIFI WIFI全称Wireless Fidelity,又称802.11b标准,它的最大优点就是传输速度较高,可以达到11Mbps,另外它的有效距离也很长,同时也与已有的各种 802.11 D ...

  9. 【转载】网络通讯协议的国际斗争

    图片发自简书App

最新文章

  1. 下面算法中,不属于公开密钥加密算法的是()。D
  2. day002-HTML知识点总结:浏览器兼容性之指定IE浏览器使用chrome内核渲染页面
  3. python基本数据类型及操作
  4. lex/flex 笔记
  5. CSDN:借助工具对【本博客访问来源】进行数据图表可视化(网友主要来自美国、新加坡、日本、英德加澳等)——记录数据来源截止日期20200718晚上22点
  6. 跟小段一起学Solaris(20)---ipFilter防火墙
  7. 线上环境部署MongoDB的官方建议
  8. SAP Spartacus table里显示较长数据时自动显示省略号的设置
  9. Fiddler抓包 | 竟然有这些骚操作,太神奇了?
  10. MobileNet-v3详解
  11. centos7 搭建本地git_小白也能看懂,30 分钟搭建个人博客!
  12. curl get请求_PHP 请求该用 cURL 还是 Guzzle ?
  13. 远程控制多台服务器,perl远程执行多台服务器shell命令
  14. 如何修改(显示)文本文档后缀名
  15. 惯性系统常用坐标系_惯性坐标系与非惯性坐标系
  16. Python-struct
  17. SFP光模块接口说明
  18. Uipath Try Catch 妙用
  19. 半监督学习之伪标签(pseudo label,entropy minimization,self-training)
  20. 三年上一大台阶,联想凌拓做对了什么?

热门文章

  1. package architecture (amd64) does not match system (arm64)
  2. Tokenizer和Split
  3. 如何将VMWare Workstation 虚拟机文件导入到ESX Server——VMX 转成 OVF 格式
  4. 十、MyBatis的缓存
  5. 小明和小强都是张老师的学生,张老师的生日是M月N日
  6. LibQQt系列之十六《QQt版本划分》
  7. JAVA 注册 HUANXIN 即时通信
  8. windows server 2003 复制其他电脑的文件到服务器,访问windows server 2003共享文件夹特别慢...
  9. 如何学习BCGControlBar?
  10. 软件工程基础个人项目——数独终局生成求解