Netty3からNetty4へのなんちゃって移植
2012/07/07追記
Netty4のAPIはその後更新され、Netty3でのAPIは残していないようです。
そのため、ここに書いた内容は現在では使えませんのでご注意ください。
2013/10/17追記
Netty3からNetty4へのちゃんとしたマイグレーション方法は「How to Migrate Netty 3 to 4 (Netty 番外編) - Taste of Tech Topics」に記載しましたので、こちらをご覧ください。
以前、Nettyのことを書いてから全然続きを書いていませんでした。その間にNettyの開発は進み、Netty3からNetty4に進化しようとしています。Nettyのgithubに行くと、開発中のNetty4のコードがあるので遊んでみました。Netty4では"next-api"と呼ばれている新しいAPIを使っているのですが、ひとまず、以前の書いたソースをNetty3からNetty4に移植してみました。すると、next-apiを使わずに、パッケージ名を変えただけでほとんど動きました。どうやら、以前のAPIも残しているようですね。
echoサンプルくらいなら、以下の2種類の修正だけで、Netty4に対応することができました(ただし、Netty4は開発中なので、APIは今後変わるかもしれません。また、使うAPIによってはNetty4でそのまま使えないかもしれません)。
- importするパッケージを"org.jboss.netty"から"io.netty"に変更する
- NioClientSocketChannelFactoryのコンストラクタ引数の変更に対応する
サンプルソースは以下の通りです。
- EchoServer
package jp.gr.java_conf.snuffkin.sandbox.netty_next.echo; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipelineFactory; import io.netty.channel.Channels; import io.netty.channel.socket.nio.NioServerSocketChannelFactory; import io.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.frame.LengthFieldPrepender; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; /** * サーバ側メインクラス */ public class EchoServer { public static void main(String[] args) { ChannelFactory factory = new NioServerSocketChannelFactory( // server Executors.newCachedThreadPool(), Executors.newCachedThreadPool() ); ServerBootstrap bootstrap = new ServerBootstrap(factory); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { ChannelPipeline pipeline = Channels.pipeline(); // Downstream(送信) pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); pipeline.addLast("stringEncoder", new StringEncoder()); // Upstream(受信) pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(8192, 0, 4, 0, 4)); pipeline.addLast("stringDecoder", new StringDecoder()); // Application Logic Handler pipeline.addLast("handler", new EchoServerHandler()); // server return pipeline; } }); bootstrap.bind(new InetSocketAddress(9999)); // 9999番ポートでlisten } }
- EchoServerHandler
package jp.gr.java_conf.snuffkin.sandbox.netty_next.echo; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelHandler; /** * サーバ側アプリケーションロジック */ public class EchoServerHandler extends SimpleChannelHandler { /** * クライアントから電文を受信した際に呼び出されるメソッド */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) { String msg = (String) event.getMessage(); // 受信電文を取りだす ctx.getChannel().write(msg); // クライアントに送信 } }
- EchoClient(NioClientSocketChannelFactoryのコンストラクタ引数を変えています)
package jp.gr.java_conf.snuffkin.sandbox.netty_next.echo; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import io.netty.bootstrap.ClientBootstrap; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipelineFactory; import io.netty.channel.Channels; import io.netty.channel.socket.nio.NioClientSocketChannelFactory; import io.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.frame.LengthFieldPrepender; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; /** * クライアント側メインクラス */ public class EchoClient { public static void main(String[] args) { ChannelFactory factory = new NioClientSocketChannelFactory( // client Executors.newCachedThreadPool() // ★引数変えています ); ClientBootstrap bootstrap = new ClientBootstrap(factory); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { ChannelPipeline pipeline = Channels.pipeline(); // Downstream(送信) pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); pipeline.addLast("stringEncoder", new StringEncoder()); // Upstream(受信) pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(8192, 0, 4, 0, 4)); pipeline.addLast("stringDecoder", new StringDecoder()); // Application Logic Handler pipeline.addLast("handler", new EchoClientHandler()); // client return pipeline; } }); ChannelFuture future = bootstrap.connect(new InetSocketAddress("localhost", 9999)); // 9999番ポートにconnect future.getChannel().getCloseFuture().awaitUninterruptibly(); bootstrap.releaseExternalResources(); } }
- EchoClientHandler
package jp.gr.java_conf.snuffkin.sandbox.netty_next.echo; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelStateEvent; import io.netty.channel.MessageEvent; import io.netty.channel.SimpleChannelHandler; /** * クライアント側アプリケーションロジック */ public class EchoClientHandler extends SimpleChannelHandler { /** * サーバに接続した際に呼び出されるメソッド */ @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent event) { ctx.getChannel().write("Hello, World!"); } /** * サーバから電文を受信した際に呼び出されるメソッド */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) { String msg = (String) event.getMessage(); System.out.println(msg); } }
これだけで、動きました。next-apiを使っていなので、これを移植と言ってはズルイ気がしますが。。。次はもうちょっと真面目に書きます^^