Netty(一)簡単なEcho Server&Cientを作成します。

13546 ワード

Netty概要
Nettyのコアコンポーネント:
  • Chanel
  • コール
  • Future
  • 事件とChanelHandler
  • ChanelChannelは、着信(入局)またはデータの流れを伝えるキャリアと見なし、オンまたはオフ、接続または切断され得る。
    一つのコールバックは実は一つの方法であり、もう一つの方法に提供された方法の参照を指す。これにより、コールバックを受ける方法は、適切なときに前者を呼び出すことができる。1つのコールバックがトリガされると、関連するイベントは、1つのinterface-ConnelHandlerの実装によって処理され得る。
    FutureFutureは、動作完了時にアプリケーションに通知する他の方法を提供しています。このオブジェクトは非同期動作の結果のプレースホルダとして考えられ、将来のある時点で完了し、その結果に対するアクセスを提供します。ChanelFutureは、1つまたは複数のChanelFutureListenerのインスタンスを登録することができるように、追加のいくつかの方法を提供している。ChanelFutureListenerの例によって提供される通知機構は、対応する動作が完了したかどうかを手動で確認する必要がなくなる。
    イベントとChanelHandlerNettyは、異なるイベントを使用して、状態の変更または操作の状態を知らせてくれます。これにより、発生したイベントに基づいて適切な動作をトリガすることができる。各イベントは、ChanelHandlerクラスのあるユーザに配信されて実現される方法である。
    Mavenを創建するプロジェクト
    プロジェクト全体のディレクトリ構造は以下の通りです。
    echo-parentのpomファイル
    
    
        4.0.0
    
        com.nasuf.echo
        echo-parent
        pom
        1.0-SNAPSHOT
    
        
            ../echo-client
            ../echo-server
        
    
        
            localhost
            9999
        
    
        
            
                io.netty
                netty-all 
                4.1.10.Final
                compile
            
        
    
        
            
                
                    maven-compiler-plugin
                
                
                    maven-failsafe-plugin
                
                
                    maven-surefire-plugin
                
                
                    org.codehaus.mojo
                    exec-maven-plugin
                
            
        
    
    
    echo-serverのpomファイル
    
    
        
            echo-parent
            com.nasuf.echo
            1.0-SNAPSHOT
            ../echo-parent/pom.xml
        
        4.0.0
    
        echo-server
    
        
            
                
                    org.codehaus.mojo
                    exec-maven-plugin
                    
                        
                            run-server
                            
                                java
                            
                        
                    
                    
                        com.echo.server.handler.EchoServer
                        
                            ${echo-server.port}
                        
                    
                
            
        
    
    
    echo-clientのpomファイル
    
    
        
            echo-parent
            com.nasuf.echo
            1.0-SNAPSHOT
            ../echo-parent/pom.xml
        
        4.0.0
    
        echo-client
    
        
            
                
                    org.codehaus.mojo
                    exec-maven-plugin
                    
                        
                            run-server
                            
                                java
                            
                        
                    
                    
                        com.echo.client.handler.EchoClient
                        
                            ${echo-server.hostname}
                            ${echo-server.port}
                        
                    
                
            
        
    
    
    そして、echo-clientとecho-serverを構築します。
    EchoServer
    EchoServer Handler
    package com.echo.server.handler;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandler.Sharable;
    import io.netty.channel.ChannelFutureListener;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.util.CharsetUtil;
    
    // @Sharable    ChannelHandler     Channel    
    @Sharable
    public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ByteBuf in = (ByteBuf) msg;
            System.out.println(
                    "Server received: " + in.toString(CharsetUtil.UTF_8));
            //             ,    ,                
            ctx.write(in);
        }
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            //             ,     Channel
            ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
                .addListener(ChannelFutureListener.CLOSE);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    
    }
    未決メッセージとは、現在ChanelOutboundBufferに一時的に保存されているメッセージで、次のflash()またはwriteAndFlash()メソッドを呼び出したときにソケットに書き込もうとするものです。
    EchoServer
    package com.echo.server.handler;
    
    import java.net.InetSocketAddress;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    public class EchoServer {
        
        private final int port;
        
        public EchoServer(int port) {
            this.port = port;
        }
        
        public void start() throws Exception {
            final EchoServerHandler serverHandler = new EchoServerHandler();
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.group(group)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer() {
    
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(serverHandler);
                        }
                    });
                //        ,       。 sync()          Thread  ,      
                ChannelFuture f = b.bind().sync();
                //      sync()  ,        ,      Channel  
                f.channel().closeFuture().sync();
            } finally {
                group.shutdownGracefully().sync();
            }
        }
        
        public static void main(String[] args) throws Exception {
            if (args.length != 1) {
                System.err.println(
                        "Usage: " + EchoServer.class.getSimpleName() + " "
                        );
                return;
            }
            int port = Integer.parseInt(args[0]);
            new EchoServer(port).start();
        }
    
    }
    まとめ:
  • EchoServer Handlerは、業務ロジック
  • を実現しました。
  • main()方法はサーバをガイドしました。
  • ガイドプロセスは以下の通りです。
  • は、サーバをガイドおよびバインディングするためのServer Boostrapの例を作成する。
  • は、NioEventLoopGroupの例を作成し、割り当てて、新規の接続および読み書きなどのイベントの処理を行う。
  • は、サーバがローカルのInetSocketAddressをバインドすることを指定する。
  • は、EchoServer Handlerの例を使用して、新しいChannelを初期化する。
  • は、サーバをバインディングするためにServer Bootstrap.bind()方法を起動する。
  • エチョーク
    Echoクライアント:
  • はサーバに接続されている。
  • は、1つまたは複数のメッセージを送信する。
  • は、各メッセージについて、サーバから返される同じメッセージを待ち、受信する。
  • 接続を閉じる
  • Echocolient Handler
    package com.echo.client.handler;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandler.Sharable;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.util.CharsetUtil;
    
    @Sharable
    public class EchoClientHandler extends SimpleChannelInboundHandler {
        
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
        }
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
            System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
        
    }
    エチョーク
    package com.echo.client.handler;
    
    import java.net.InetSocketAddress;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    
    public class EchoClient {
        
        private final String host;
        private final int port;
        
        public EchoClient(String host, int port) {
            this.host = host;
            this.port = port;
        }
        
        public static void main(String[] args) throws Exception {
            if (args.length != 2) {
                System.err.println(
                        "Usage: " + EchoClient.class.getSimpleName() +
                        "  ");
                return;
            }
            String host = args[0];
            int port = Integer.parseInt(args[1]);
            new EchoClient(host, port).start();
        }
        
        public void start() throws Exception {
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                Bootstrap b = new Bootstrap();
                b.group(group)
                 .channel(NioSocketChannel.class)
                 .remoteAddress(new InetSocketAddress(host, port))
                 .handler(new ChannelInitializer() {
    
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new EchoClientHandler());
                    }
                     
                 });
                ChannelFuture f = b.connect().sync();
                f.channel().closeFuture().sync();
            } finally {
                group.shutdownGracefully().sync();
            }
        }
    
    }
    まとめ:
  • は、クライアントを初期化するために、Bootstrapの例を作成する。
  • は、イベント処理を行うためにNioEventLoopGroupの例を割り当て、イベント処理は、新たな接続を作成することと、入局および出局データを処理することとを含む。
  • は、サーバ接続のためのInetSocketAddressの例を作成する。
  • 接続が確立されると、Echocolient Handlerの例がChannelのChanelPipelineにインストールされます。
  • すべての設定が完了したら、Bootstrap.co nnect()方法を呼び出してリモートノードに接続する。
  • テストを実行
    echo-parentディレクトリに入って実行します。
    mvn clean package
    その後、それぞれサービス端末とクライアントで実行される:
    mvn exec:java
    サービス先で見られます。
    $ mvn exec:java
    [INFO] Scanning for projects...
    [INFO] 
    [INFO] ------------------------------------------------------------------------
    [INFO] Building echo-server 1.0-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO] 
    [INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ echo-server ---
    クライアントで見ました:
    $ mvn exec:java
    [INFO] Scanning for projects...
    [INFO] 
    [INFO] ------------------------------------------------------------------------
    [INFO] Building echo-client 1.0-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO] 
    [INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ echo-client ---
    Client received: Netty rocks!
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 3.903 s
    [INFO] Finished at: 2018-11-18T20:54:08+08:00
    [INFO] Final Memory: 11M/309M
    [INFO] ------------------------------------------------------------------------
    クライアントの実行が完了し、終了しました。サービスカウンターのウィンドウに戻ると、次のような情報が見られます。
    Server received: Netty rocks!
    『Netty実戦』第二章