前回の記事で少しふれた「Netty in Action」が発売されました。ただし、現段階ではEarly Accessということで、PDFで一部の章のみが公開されています。ネットワークプログラミングの基本的な所から丁寧に説明されており、今後、執筆が進むのが楽しみです。
ところで、Nettyは最新安定版がversion3なのですが、version4の開発も進められています。このブログではversion3について紹介していますが、Netty in Actionはversion4のAPIを使って記述しているので、ご注意ください。version3とversion4では、概念的には大きく変わっていませんが、パッケージ名・クラス名・メソッド名等は大幅に変わっています。
それでは、本日もよろしくお願いします。
これまで、「導入編」「導入編2」として、Nettyを使ったエコーサーバのサンプルを見てきました。今回は「導入編3」として、これまでに紹介したコードを使ってNettyの使い方を解説します。
ソースコードの内容説明
EchoServerのサンプルを使って、Nettyのコードで解説します。Client側もほとんど同じですので、Client側の解説は省略します。
- EchoServer
/** * サーバ側メインクラス */ public class EchoServer { public static void main(String[] args) { ChannelFactory factory = new NioServerSocketChannelFactory( // server ★1 Executors.newCachedThreadPool(), Executors.newCachedThreadPool() ); ServerBootstrap bootstrap = new ServerBootstrap(factory); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { // ★2 public ChannelPipeline getPipeline() { ChannelPipeline pipeline = Channels.pipeline(); // Downstream(送信) pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); // ★3 pipeline.addLast("stringEncoder", new StringEncoder()); // ★4 // Upstream(受信) pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(8192, 0, 4, 0, 4)); // ★5 pipeline.addLast("stringDecoder", new StringDecoder()); // ★6 // Application Logic Handler pipeline.addLast("handler", new EchoServerHandler()); // server ★7 return pipeline; } }); bootstrap.bind(new InetSocketAddress(9999)); // 9999番ポートでlisten } }
★1 ServerSocketChannelFactory
Nettyで利用するIO処理の種類を指定します。OioServerSocketChannelFactory、NioServerSocketChannelFactoryが指定できます。
ここに登場するOIO、NIOというのはJavaのコネクション処理の仕組みです。OIOは大量のコネクションを処理しづらい仕組みだったため、NIOという概念が登場し、大量のコネクションを処理できるようになりました。Nettyでは、Factoryの宣言を変更するだけで、どちらも利用可能です。
★2 Pipeline
NettyはPipelineという機能を利用して電文処理を行います。
送信処理はDownstream、受信処理はUpstreamと呼ばれています。Handlerという「電文処理を行うクラス」を組合せてPipelineを作成することにより、電文処理を再利用可能なHandlerを使ってレイヤー化することができます。
この概念をChannelPipelineのJavadocから引用すると、以下の通りです。上の方がアプリケーション側で、下の方がネットワーク側。なので、送信がDownで、受信がUpです。
I/O Request via Channel or ChannelHandlerContext | +----------------------------------------+---------------+ | ChannelPipeline | | | \|/ | | +----------------------+ +-----------+------------+ | | | Upstream Handler N | | Downstream Handler 1 | | | +----------+-----------+ +-----------+------------+ | | /|\ | | | | \|/ | | +----------+-----------+ +-----------+------------+ | | | Upstream Handler N-1 | | Downstream Handler 2 | | | +----------+-----------+ +-----------+------------+ | | /|\ . | | . . | | [ sendUpstream() ] [ sendDownstream() ] | | [ + INBOUND data ] [ + OUTBOUND data ] | | . . | | . \|/ | | +----------+-----------+ +-----------+------------+ | | | Upstream Handler 2 | | Downstream Handler M-1 | | | +----------+-----------+ +-----------+------------+ | | /|\ | | | | \|/ | | +----------+-----------+ +-----------+------------+ | | | Upstream Handler 1 | | Downstream Handler M | | | +----------+-----------+ +-----------+------------+ | | /|\ | | +-------------+--------------------------+---------------+ | \|/ +-------------+--------------------------+---------------+ | | | | | [ Socket.read() ] [ Socket.write() ] | | | | Netty Internal I/O Threads (Transport Implementation) | +--------------------------------------------------------+
★3〜4
Downstream処理をStringEncoder→LengthFieldPrependerの順で行います。
StringEncoderはStringをバイト配列(電文データ)に変換します。LengthFieldPrependerはバイト配列に電文長を付与します。
この2つのHandlerを組合せて利用することで、Stringを「データの先頭に電文長があり、その後に実際の電文内容が続く」という電文に変換することができます。
★5〜6
Upstream処理をLengthFieldBasedFrameDecoder→StringDecoderの順で行います(DownとUpで順序が逆になります)。LengthFieldBasedFrameDecoderは電文長を解析し、電文長にしたがってバイト配列を取り出します。StringDecoderはバイト配列をStringに変換します。
この2つのHandlerを組合せて利用することで、「データの先頭に電文長があり、その後に実際の電文内容が続く」という電文をStringに変換することができます。
★7
アプリケーションのロジックを記述するクラスを指定します。
レイヤー化、部品化の良いところ
NettyではPipeline、Handlerを利用することで、処理をレイヤー化、部品化することができます。例えば、先ほどのHandlerにSSL処理を行うSslHandlerを加えるだけで、SSL通信が実現できます。
また、Handlerを変更することにより、使用するプロトコルを変えることができます。Nettyでは、http、WebSocket、Protocol Buffers、SPDY等、様々なプロトコルを利用するためのHandlerが用意されています。これは便利ですね。
さて、今回で導入編は終了です。Nettyの紹介を駆け足で行ってきましたが、いかがだったでしょうか。Nettyの力強さが少しでも伝われば、幸いです。
それではまた〜