Netty實戰之(一)入門示例

Netty是什麼?

Netty是一個異步的、事件驅動的網絡編程框架,用於快速開發可維護的、高性能的網絡服務器、客戶端應用程序。


Netty實戰之(一)入門示例

Netty特點

  1. 簡單易用,提供統一的API來支持阻塞式及非阻塞式I/O。
  2. 靈活、可擴展的事件模型,更容易實現清晰的關注點分離。
  3. 可定製的線程模型,單線程、多線程、多級事件驅動。
  4. 高吞吐、低延遲。
  5. 更少的資源佔用。
  6. 最少化不必要的內存拷貝。

引入Netty依賴

<code>        <dependency>            <groupid>io.netty/<groupid>            <artifactid>netty-handler/<artifactid>            <version>4.1.45.Final/<version>        /<dependency>        <dependency>            <groupid>ch.qos.logback/<groupid>            <artifactid>logback-classic/<artifactid>            <version>1.2.3/<version>        /<dependency>        <dependency>            <groupid>junit/<groupid>            <artifactid>junit/<artifactid>            <version>4.11/<version>            <scope>test/<scope>        /<dependency>/<code>

創建服務端

創建服務端應用的代碼如下

<code>    @Test    public void testNettyServer() {        // 0        NioEventLoopGroup parentGroup = new NioEventLoopGroup(1);        NioEventLoopGroup childGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors() << 1);        try {            new ServerBootstrap()// 1                    .group(parentGroup, childGroup)// 2                    .channel(NioServerSocketChannel.class)//3                    .handler(new LoggingHandler())//4                    .childHandler(new ChannelInitializer<socketchannel>() {// 5                        @Override                        protected void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline()                                    .addLast(new LengthFieldBasedFrameDecoder(2048, 0, 4, 0, 4))                                    .addLast(new StringDecoder())                                    .addLast(new LengthFieldPrepender(4, 0))                                    .addLast(new StringEncoder())                                    .addLast(new SimpleChannelInboundHandler<string>() {// 5.1                                        @Override                                        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {                                            log.info("msg from client: {}", msg);                                            ctx.writeAndFlush(msg);                                        }                                    });                        }                    })                    .option(ChannelOption.SO_BACKLOG, 512)// 6                    .childOption(ChannelOption.SO_KEEPALIVE, true)// 7                    .bind(new InetSocketAddress(2020)).sync()// 8                    .addListener(future -> log.info("Netty服務端綁定端口完成,等待客戶端鏈接......"))                    .channel().closeFuture().sync()// 9            ;        } catch (Exception e) {            log.error("Netty服務器啟動失敗", e);        } finally {// 10            parentGroup.shutdownGracefully();            childGroup.shutdownGracefully();        }    }/<string>/<socketchannel>/<code>
  1. NioEventLoopGroup是用於處理I/O操作的多線程事件循環器,這裡創建的兩個實例分別用於處理服務端、客戶端 I/O操作。
  2. ServerBootstrap用於構建服務端Channel實例。
  3. 指定了用於處理I/O操作的NioEventLoopGroup實例。
  4. 這裡指定了使用NioServerSocketChannel,即服務端將使用非阻塞式I/O來處理客戶端鏈接、請求、響應。
  5. 用於服務端的Handler實例。
  6. 創建一個ChannelHandler實例。
  7. 設置服務端Socket參數。
  8. 設置客戶端鏈接的Socket參數。
  9. 綁定端口並開始接受客戶端鏈接。
  10. 等待直到服務端Socket關閉。(這裡不會發生)
  11. 關閉NioEventLoopGroup。

這樣,一個簡單的服務端應用就開發完成了。

創建客戶端

創建客戶端應用的代碼如下

<code>    @Test    public void testNettyClient() {        // 0        NioEventLoopGroup group = new NioEventLoopGroup(1);        try {            Channel channel = new Bootstrap()// 1                    .group(group)// 2                    .channel(NioSocketChannel.class)// 3                    .handler(new ChannelInitializer<socketchannel>() {// 4                        @Override                        protected void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline()                                    .addLast(new LengthFieldBasedFrameDecoder(2048, 0, 4, 0, 4))                                    .addLast(new StringDecoder())                                    .addLast(new LengthFieldPrepender(4, 0))                                    .addLast(new StringEncoder())                                    .addLast(new SimpleChannelInboundHandler<string>() {// 4.1                                        @Override                                        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {                                            log.info("msg from server: {}", msg);                                        }                                    });                        }                    })                    .option(ChannelOption.SO_KEEPALIVE, true)// 5                    .option(ChannelOption.TCP_NODELAY, true)                    .connect(new InetSocketAddress(2020)).sync()// 6                    .addListener(future -> log.info("Netty客戶端已鏈接到服務端"))                    .channel();            // 7            channel.writeAndFlush("Hello, Netty!").addListener(future -> log.info("Netty客戶端發送數據完成"));            // 8            channel.closeFuture().sync();        } catch (Exception e) {            log.error("Netty客戶端啟動失敗", e);        } finally {// 9            group.shutdownGracefully();        }    }/<string>/<socketchannel>/<code>
  1. 創建NioEventLoopGroup實例。
  2. Bootstrap用於幫助構建客戶端Channel實例。
  3. 指定用於處理I/O操作的NioEventLoopGroup實例。
  4. 同服務端類似,這裡指定創建NioSocketChannel的實例。
  5. 創建一個ChannelHandler實例。
  6. 設置客戶端鏈接的Socket參數。
  7. 鏈接到指定的服務器及端口,這裡服務器是本機。
  8. 使用創建的NioSocketChannel實例向服務端發送數據。
  9. 等待直到NioSocketChannel實例關閉。
  10. 關閉NioEventLoopGroup實例。

客戶端也創建完了。

分別啟動服務端示例、客戶端示例,日誌中可以看到服務端、客戶端已經可以正常通信了。

總結

以上開發了簡單的服務器、客戶端示例程序,從中可以看出,使用Netty開發網絡應用的簡單、易用性;同時也可以看出,Netty構建服務端、客戶端的API基本是統一的。

文章僅展現了服務器、客戶端示例程序,後續文章將對代碼中涉及的以下相關內容進行簡單的探討學習。

  • NioEventLoopGroup
  • NioServerSocketChannel、NioSocketChannel
  • ChannelInitializer、ChannelHandler
  • LengthFieldBasedFrameDecoder、LengthFieldPrepender
  • StringDecoder、StringEncoder
  • SimpleChannelInboundHandler


分享到:


相關文章: