高性能NIOフレームワークNetty入門編

5669 ワード

Netty紹介NettyはJBOSSが提供するjavaオープンソースフレームワークです.Nettyは、高性能で信頼性の高いネットワークサーバとクライアントプログラムを迅速に開発するために、非同期でイベント駆動のネットワークアプリケーションフレームワークとツールを提供します.つまり、NettyはNIOベースのお客様、サーバ側のプログラミングフレームワークであり、Nettyを使用すると、あるプロトコルを実現したお客様、サービス側のアプリケーションなど、ネットワークアプリケーションを迅速かつ簡単に開発することができます.Nettyは、TCPおよびUDPのsocketサービス開発など、ネットワークアプリケーションのプログラミング開発プロセスをかなり簡略化し、ストリーミング化している.公式サイトのアドレス:http://netty.io/シーンNettyを使用して主流のNIOフレームワークになったのは、次のような利点があるからです.
  • NIOのクラスライブラリやAPIの使用難易度が高く、Nettyがカプセル化されており、使いやすい
  • 高性能、強力、多種類のコーデック機能をサポート、多種類の主流プロトコルをサポート
  • 成熟、安定、すでに複数の大型フレームで使用されている(dubbo,RocketMQ,Hadoop,mycat,Spring 5)
  • ・・・数年前にうちの会社でIMのシステムを開発するためにMinaを使っていましたが、Minaも良いフレームワークでした(http://mina.apache.org/).今では多くのフレームワークがNettyで下位通信に変更されています.当社には今、Minaで書かれた代理フレームワークがあります.Nettyを散歩して再構築することができます.皆さんは上記の紹介を見て、Nettyがどんなシーンで使えるか知っているかどうか分かりませんが、私が前にやったことと結びつけて詳しく説明します.もちろんシーンの一方を使うだけです.前にキャプチャを行う时、いくつかの小型のウェブサイトがあって、ページの构造は比较的に复雑で、また登录などの操作が必要で、このような统一的なキャプチャシステムでキャプチャすることができなくて、シナリオを书く方式を通じて具体的なウェブサイトに対してキャプチャすることしかできなくて、キャプチャの必须の1つの条件は代理IPで、便利にキャプチャするために、わざわざ1つのキャプチャのSDKをカプセル化して、キャプチャの方法を提供して、スイッチングエージェントが内蔵されています.私达は1つのエージェントプールのサービスがあって、1つのウェブサイトを通じて(通って)使用することができるエージェントのIPを取得して、ちょうど使うHttpの要求でエージェントのIPを取得して、キャプチャの量が比较的に大きいため、Httpの要求を通じて(通って)エージェントのIPの効率を取得することができなくて、后でNettyでIPのこの部分を取得することを改造して、Netty長い接続方式により、Http要求が毎回接続を確立することによる性能消費の問題を回避し、バイナリのデータ伝送によってネットワークオーバーヘッドを低減し、性能がより高い.簡単な入門私達は1つのサービス側とクライアントを編纂して、クライアントはサービス側に1本のメッセージを送信して、メッセージの伝送はまず文字列で伝達して、サービス側はクライアントが送信したメッセージを受け取って、それから1本のメッセージに返事します.まずサービス側コード作成:
    public class ImServer {
    public void run(int port) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer() { 
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast("decoder", new StringDecoder());
                        ch.pipeline().addLast("encoder", new StringEncoder());
                        ch.pipeline().addLast(new ServerStringHandler());
                    }
                })
                .option(ChannelOption.SO_BACKLOG, 128)
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        try {
            ChannelFuture f = bootstrap.bind(port).sync();
             f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
    }
  • ServerBootstrapによるサービスの構成と、socketのパラメータはServerBootstrapによる設定が可能です.
  • group法により2つのスレッドグループが関連付けられており、NioEventLoopGroupはI/O操作を処理するためのスレッドプールであり、1つ目は「boss」、acceptクライアント接続、2つ目は「worker」、クライアントデータの読み書き操作を処理する.もちろん、接続と読み書きを同時に処理するNioEventLoopGroupを1つだけ使用することもできます.bootstrap.group()メソッドはパラメータをサポートします.
  • channel指定NIO方式
  • childHandler具体的なデータ処理方式を配置するためのもので、コーデックを指定し、データを処理するHandler
  • バインドポート起動サービスメッセージ処理:
    /**
    *     
    * @author yinjihuan
    *
    */
    public class ServerStringHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.err.println("server:" + msg.toString());
        ctx.writeAndFlush(msg.toString() + "  ");
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
    }
    起動サービス、指定ポート2222:
    public static void main(String[] args) {
    int port = 2222;
    new Thread(() -> {
        new ImServer().run(port);
    }).start();
    }
             :
    public class ImConnection {
    private Channel channel;
    public Channel connect(String host, int port) {
        doConnect(host, port);
        return this.channel;
    }
    private void doConnect(String host, int port) {
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.handler(new ChannelInitializer() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {    
                    ch.pipeline().addLast("decoder", new StringDecoder());
                    ch.pipeline().addLast("encoder", new StringEncoder());
                    ch.pipeline().addLast(new ClientStringHandler());
                }
            });
            ChannelFuture f = b.connect(host, port).sync();
            channel = f.channel();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    }
    クライアントメッセージ処理:
    /**
    *                 
    * @author yinjihuan
    *
    */
    public class ClientStringHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        System.out.println("client:" + msg.toString());
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
    }
    クライアント起動ポート、そしてサービス側へメッセージ送信:
    public static void main(String[] args) {
    String host = "127.0.0.1";
    int port = 2222;
    Channel channel = new ImConnection().connect(host, port);
    channel.writeAndFlush("yinjihuan");
    }
    テスト手順:
  • まずはサービス側を起動
  • クライアント起動、メッセージ送信
  • サービス側メッセージ受信、コンソール出力server:yinjihuan
  • クライアントはサービス側からの返信メッセージを受け取り、コンソールには出力client:yinjihuanのソースコードの参考があります.https://github.com/yinjihuan/netty-im