唯一のバイトのシーケンスとして、元のデータのネットワーク伝送です。何が、その後、私たちのアプリケーションは、意味のある情報のこれらのバイトシーケンスを必要とします。アプリケーションデータは、ネットワーク形式に変換され、両方の機能がコーデックと呼ばれる単一の要素を有しながら、ネットワーク構成要素の形式は、データがエンコーダとデコーダと呼ばれるアプリケーションを変換します。
1、&スティックパッケージ開梱
上記の分析に基づいて、我々はダボリモート呼び出しは、TCP / IPソケットベースの通信に基づいて、仁王ネッティーフレームワークを知っています。
TCPは、合意の「流れ」である、いわゆるストリームは、データの列に制限はありません。あなたは何の境界線がありません、その間、水の川が連続していると想像することができます。TCPは、下にある上位層サービスデータの特定の意味を知らない、その操作は、完全なTCPパケットが送信される複数のパケットに分割することができるように、TCPパケットバッファの実際のケースに基づいて分割されます。TCPパケットとアンパック粘着性の問題と呼ばれ、より大きなパケットの送信、に小さな複数のパケットをパッケージ化することも可能です。
1.1 TCPスティックパッケージ&問題の開梱説明
ここでは、次の図で粘度の問題を開梱TCPパケットを説明します。
時間バイト読取りデータが不確実であることから、それは以下の4例かもしれサーバー、サーバーへのクライアントの送信二つのパケットD1およびD2を仮定します。
- 二回サーバは、2つの別々のデータパケット、それぞれD1およびD2を、読み、開梱パッケージを付着しないように
- サーバは、TCPパケットの被着体と呼ばれる2つのは、D1およびD2は、互いに結合されているパケットを受信します
- TCPアンパックと呼ばれるパケットの完全なパケットD1およびD2、内部パケットD2第2読み出しの残りの内側部分に2つのデータパケット、最初の読み取りを読み取る回サーバ
- D1、D1_2全体パッケージ内の残りのパッケージのパケットD1及びD2への第2の読み出し - パッケージ内部D1_1に2つのデータパケット、最初の読み出し部分を読み取る回サーバ。
この時点で、サーバーが受信した場合、TCPスライディングウィンドウは非常に小さく、かつデータパケットD1およびD2が比較的大きく、そのサービスは、ポイントに完全なパケット受信D1およびD2に数回終了時に数回発生します第五に発生する可能性があります開梱。
1.2&スティックパッケージ開梱を解きます
基本的なTCP上位層サービスデータを理解することができないので、パケットに分割して再結合されていないの下部に保証するものではありません。この問題は、主流ソリューション、上位層プロトコルスタックの設計を適用することによって解決することができます。
- 十分なスペースが空白の場合、メッセージの長さは、例えば、各パケットのサイズは、200バイトの固定長です。
- トレーラーキャリッジリターンの増加分割、例えばTFPプロトコル
- メッセージヘッダとメッセージ本体にメッセージ、メッセージヘッダは、メッセージ(またはメッセージボディの長さ)フィールドの合計長さを示す情報を含みます。
最初の二つの場合ネッティーは独自の実現を持っている、とダボを使用し、問題と開梱を解決するためにスティック包装の3種類があります。
2、ダボのカスタムプロトコル
ネッティーは、開発者のために、実際には、このコンポーネントChannelHandlerを動作させます。我々は送信するためにネットワークを分析し、受信する前にダボ要求はのNettyServerHandler ChannelHandlerを達成することです。達成するためにChannelHandlerコーデックも行われます。
NettyServer#doOpen
protected void doOpen() throws Throwable {
bootstrap = new ServerBootstrap();
bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
new DefaultThreadFactory("NettyServerWorker", true));
final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
channels = nettyServerHandler.getChannels();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
.childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
.addLast("decoder", adapter.getDecoder())
.addLast("encoder", adapter.getEncoder())
.addLast("handler", nettyServerHandler);
}
});
// bind
ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
channelFuture.syncUninterruptibly();
channel = channelFuture.channel();
}
ChannelHandlerは、コード復号および実装クラスChannelPipelineに応答して、要求を処理する初期化添加した場合、特に、露光のサービス時間を行います。ダボ特定のコーデックはNettyCodecAdapterによって処理されます。
ここでは、ダボプロトコルヘッダの規則を見てみましょう。
プロトコルヘッダとして16バイト配列の長さを有するダボ。8 1つのバイトに対応します。従ってダボプロトコルヘッダ128ビット(0から127まで、すなわち図)。私たちは、この128のプロトコルヘッダを見て、それが何を意味するかを表します。
- 0〜7:ダボマジックナンバー(
(short) 0xdabb
)高い、すなわち(ショート)0xda。 - 8〜15:ダボマジックナンバー(
(short) 0xdabb
)が低い、すなわち(ショート)0xbb。 - 16 ~ 20:序列化 id(Serialization id),也就是 dubbo 支持的序列化中的
contentTypeId
,比如 Hessian2Serialization#ID 为 2 - 21 :是否事件(event )
- 22 : 是否 Two way 模式(Two way)。默认是 Two-way 模式,
<dubbo:method>
标签的 return 属性配置为false,则是oneway模式 - 23 :标记是请求对象还是响应对象(Req/res)
- 24 ~ 31:response 的结果响应码 ,例如 OK=20
- 32 ~ 95:id(long),异步变同步的全局唯一ID,用来做consumer和provider的来回通信标记。
- 96 ~ 127: data length,请求或响应数据体的数据长度也就是消息头+请求数据的长度。用于处理 dubbo 通信的粘包与拆包问题。
我们就根据源码来分析一下 dubbo 是如何进行编解码的。
3、协议源码分析
dubbo 的编解码可以分为以下 4 个部分来分析:
- consumer 请求编码
- consumer响应结果解码
- provider 请求解码
- provider 响应结果编码
在 dubbo 进行服务暴露的时候是通过 NettyCodecAdapter 来获取到需要添加的编码器与解码器。在 NettyCodecAdapter 里面定义内部类 InternalEncoder (继承 netty 中的 MessageToByteEncoder)实现 dubbo 的自定义编码器,定义内部类 ByteToMessageDecoder (继承 netty 中的 ByteToMessageDecoder) 实现 dubbo 自定义解码器。不管是自定义的编码器还是解码器最终都会调用到 dubbo 的 SPI 接口 Codec2 默认使用 DubboCodec。下面就具体的分析一下 dubbo 这 4 个编解码过程。
3.1消費者の要求エンコーディング
ときに、消費者の要求プロバイダーRequestオブジェクトは、それがコーディング必要とするプロセスであるので、バイト配列に変換する必要があります。
デコード結果に3.2消費者の反応
バイト配列Responseオブジェクトに変換するために、消費者のプロバイダのニーズに応答を受信すると、それはニーズをデコードする処理です。
3.3プロバイダ要求デコーダ
消費者の要求を受信プロバイダは、それがニーズをデコードする処理である、バイト配列Requestオブジェクトに変換する必要があります。
3.4符号化された応答結果
消費者の要求は、結果はそれがコーディング必要とするプロセスであるので、バイト配列Responseオブジェクトに変換する必要が処理されると、プロバイダ応答が必要です。