Netty前回のエントリから、ちょっと時間が空いてしまいました...。1と2をリリースNettyが3.3.1にバージョンアップとまあ、ちょっと置いてかれてる感じですね。2.10はまだMilestoneリリースなのと、Nettyに関する勉強が中途半端なのでまだ置いておきます。Nettyはバージョンアップしているものの、UserGuideドキュメントは変わっていないので、変わらずこれを続けられそうです。Startedを進めていくとしましょう。今日のテーマはこちら。Transport]http://netty.io/docs/stable/guide/html/#start.10今回は、訳が中心なりそうです。ソケットバッファに対する、小さな警告http://netty.io/docs/stable/guide/html/#start.10.2TCP/IPのようなストリームベースの輸送では、受信したデータをソケットの受信バッファに保存します。残念ながら、ストリームベースで運ばれたバッファは、パケットのキューではなくバイトのキューです。これは、あなたが2つの独立したパケットで2つのメッセージを送信したとしても、OSは2つのメッセージではなく単なるバイトの束として扱ってしまうことを意味します。そのため、リモートクライアントが書き出したデータを正確に読み取ることは保証されていません。OSのTCP/IPスタックが、次のような3のパケットを受け取ったと仮定しましょう。+-----+-----+-----+ストリームベースのプロトコルの一般的な特性のため、あなたのアプリケーションは次のような断片(フラグメント)となった形式を読み込んでしまう可能性が十分にあります。+----+-------+---+---+したがって、受信データを、サーバサイド、クライアントサイドに関係なく、アプリケーションロジックにより容易に理解できる意味のある構造に再配置するべきです。上記の例の場合は、受信データが下記の様な構造となるべきです。+-----+-----+-----+最初の解答http://netty.io/docs/stable/guide/html/#start.10.3TIMEクライアントの例に戻りましょう。私達は同じ問題を抱えています。32ビット整数は非常に少ないデータであり、多くの場合フラグメント化されていないでしょう。問題はフラグメント化されているかもしれない、ということです。トラフィックが増加するにしたがってフラグメント化する可能性も上昇していくでしょう。極端に単純化した解は、累積できる内部バッファを作成し、すべての4バイトデータが内部バッファに受信されるまで待つことです。下記は、その問題を解決するTimeClientHandlerクラスの実装です。}}(19)dynamicBufferとは、要求に応じて容量の増加するChannelBufferです。メッセージの長さを知らない場合に、非常に役に立ちます。(20)最初に、全ての受信したデータは変数bufへまとめられるべきです。(21)ハンドラはbufが十分なデータ(この例では4バイト)を持っているかどうか、チェックしなくてはなりません。実際のビジネスロジックに移ります。2つ目の解答http://netty.io/docs/stable/guide/html/#start.10.4最初の解答では、TIMEクライアントでの問題を解決しましたが、修正されたハンドラは美しくありません。可変長フィールドのように多数のフィールドからできているような、より複雑なプロトコルを思い浮かべます。あなたのChannelHandlerの実装は、早期にメンテナンスができなくなるでしょう。あなたは気付いているかもしれませんが、あなたは1つ以上のChannelHandlerをChannelPipelineに加えることができます。そのため、あなたは一枚岩であったChannelHandlerを、アプリケーションの複雑さを小さくするため多くのモジュールとして分割することができます。TimeClientHandlerは2つのハンドラへ分割することができました。TimeDecoderはフラグメントの問題を取扱い、TimeClientHandlerは、最初のシンプルなバージョンにします幸いNettyは、あなたが自由にアプリケーションを記述をすることを助けてくれる、拡張可能なクラスを提供しています。}}(22)FrameDecoderは、フラグメントの問題を簡単に扱えるようにするための、ChannelHandlerの実装です。(23)FrameDecoderは、新しいデータを受信した時、内部に保持された累積バッファを引数にdecodeメソッドを呼び出します。(24)戻り値としてnullを戻した時、データがまだ十分に得られていないことを意味します。十分なデータがある場合、FrameDecoderは再度decodeメソッドを呼び出すでしょう。(25)null以外の値を戻した場合、それはdecodeメソッドがメッセージの復号に成功したことを意味します。FrameDecoderは、内部の累積バッファの読み取り部を破棄するでしょう。ここで、多数のメッセージを復号する必要はないことを覚えておいてください。FrameDecoderは、nullが返されるまでdecoderメソッドを呼び出し続けるでしょう。今、ChannelPipelineにもうひとつのハンドラを加えます。TimeClientのChannelPipelineFactoryの実装を修正しましょう。})もしあなたが冒険好きなら、デコーダをもっと単純化するReplayingDecoderを試してみたいと思うかもしれません。詳しい情報は、APIリファレンスを参照する必要があります。}}さらに、Nettyはほとんどのプロトコルを容易に実装することを可能にし、一枚岩でメンテナンスの難しいハンドラを実装してしまうことを避けるられるような、独創的なデコーダ群を提供しています。多くの詳細な例については、次のパッケージを参照してください。テキストベースのプロトコルの例ん〜、なかなか疲れましたわ〜。Serverを、SSL化するそろそろ、Nettyを使ったSSLサーバの作成をやってみようと思い...2012-04-28Nettyで簡易HTTPサーバを書く久しぶりにNettyネタです。今回は写経ものですが。ところ...2012-03-31Pipelineに組み込まれたChannelHandlerの実行順を確認する[クライアント編&まとめ...前に、NettyのTelnetサーバのサンプルを写経して、Pipelineに組...2012-03-25NettyのPipelineとChannelHandlerの関係を学ぶ久々にNettyです。Guidの最後のチュートリアルです。5はてなブログをはじめよう!Kazuhiraさんは、はてなブログを使っています。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。