1. 程式人生 > >Netty學習:搭建一個簡單的Netty服務(JAVA NIO 類庫的非同步通訊框架)

Netty學習:搭建一個簡單的Netty服務(JAVA NIO 類庫的非同步通訊框架)

http://wosyingjun.iteye.com/blog/2303296

Netty學習:搭建一個簡單的Netty服務

Netty 是一個基於 JAVA NIO 類庫的非同步通訊框架,它的架構特點是:非同步非阻塞、基於事件驅動、高效能、高可靠性和高可定製性。換句話說,Netty是一個NIO框架,使用它可以簡單快速地開發網路應用程式,比如客戶端和服務端的協議。Netty大大簡化了網路程式的開發過程比如TCP和UDP的 Socket的開發。Netty 已逐漸成為 Java NIO 程式設計的首選框架。

一. Netty 的優點:

  • API 使用簡單,開發門檻低;
  • 功能強大,預置了多種編解碼功能,支援多種主流協議;
  • 定製能力強,可以通過 ChannelHandler 對通訊框架進行靈活的擴充套件;
  • 效能高,通過與其它業界主流的 NIO 框架對比,Netty 的綜合性能最優;
  • 社群活躍,版本迭代週期短,發現的 BUG 可以被及時修復,同時,更多的新功能會被加入;
  • 經歷了大規模的商業應用考驗,質量得到驗證。在網際網路、大資料、網路遊戲、企業應用、電信軟體等眾多行業得到成功商用,證明了它完全滿足不同行業的商用標準。

二. 搭建Netty服務:

  1. 新增pom依賴
    Pom程式碼  收藏程式碼
    1. <dependency>  
    2.     <groupId>io.netty</groupId>  
    3.     <artifactId>netty-all</artifactId>  
    4.     <version>4.1.0.Final</version>  
    5. </dependency>  
     
  2. SimpleServer(服務端)
    Java程式碼  收藏程式碼
    1. package com.yingjun.netty.server;  
    2. import io.netty.bootstrap.ServerBootstrap;  
    3. import io.netty.channel.ChannelFuture;  
    4. import io.netty.channel.ChannelInitializer;  
    5. import io.netty.channel.ChannelOption;  
    6. import io.netty.channel.EventLoopGroup;  
    7. import io.netty.channel.nio.NioEventLoopGroup;  
    8. import io.netty.channel.socket.SocketChannel;  
    9. import io.netty.channel.socket.nio.NioServerSocketChannel;  
    10. /** 
    11.  *  
    12.  * Netty中,通訊的雙方建立連線後,會把資料按照ByteBuf的方式進行傳輸, 
    13.  * 例如http協議中,就是通過HttpRequestDecoder對ByteBuf資料流進行處理,轉換成http的物件。 
    14.  *  
    15.  */
    16. publicclass SimpleServer {  
    17.     privateint port;  
    18.     public SimpleServer(int port) {  
    19.         this.port = port;  
    20.     }  
    21.     publicvoid run() throws Exception {  
    22.         //EventLoopGroup是用來處理IO操作的多執行緒事件迴圈器
    23.         //bossGroup 用來接收進來的連線
    24.         EventLoopGroup bossGroup = new NioEventLoopGroup();   
    25.         //workerGroup 用來處理已經被接收的連線
    26.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
    27.         try {  
    28.             //啟動 NIO 服務的輔助啟動類
    29.             ServerBootstrap b = new ServerBootstrap();   
    30.             b.group(bossGroup, workerGroup)  
    31.                 //配置 Channel
    32.                 .channel(NioServerSocketChannel.class)  
    33.                 .childHandler(new ChannelInitializer<SocketChannel>() {   
    34.                         @Override
    35.                         publicvoid initChannel(SocketChannel ch) throws Exception {  
    36.                             // 註冊handler  
    37.                             ch.pipeline().addLast(new SimpleServerHandler());  
    38.                         }  
    39.                     })  
    40.                 .option(ChannelOption.SO_BACKLOG, 128)   
    41.                 .childOption(ChannelOption.SO_KEEPALIVE, true);   
    42.             // 繫結埠,開始接收進來的連線
    43.             ChannelFuture f = b.bind(port).sync();  
    44.             // 等待伺服器 socket 關閉 。
    45.             f.channel().closeFuture().sync();  
    46.         } finally {  
    47.             workerGroup.shutdownGracefully();  
    48.             bossGroup.shutdownGracefully();  
    49.         }  
    50.     }  
    51.     publicstaticvoid main(String[] args) throws Exception {  
    52.         new SimpleServer(9999).run();  
    53.     }  
    54. }  
     
  3. SimpleServerHandler(服務端請求處理Handler)
    Java程式碼  收藏程式碼
    1. package com.yingjun.netty.server;  
    2. import io.netty.buffer.ByteBuf;  
    3. import io.netty.channel.ChannelHandlerContext;  
    4. import io.netty.channel.ChannelInboundHandlerAdapter;  
    5. publicclass SimpleServerHandler extends ChannelInboundHandlerAdapter {  
    6.     @Override
    7.     publicvoid channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
    8.         System.out.println("SimpleServerHandler.channelRead");  
    9.         ByteBuf result = (ByteBuf) msg;  
    10.         byte[] result1 = newbyte[result.readableBytes()];  
    11.         // msg中儲存的是ByteBuf型別的資料,把資料讀取到byte[]中
    12.         result.readBytes(result1);  
    13.         String resultStr = new String(result1);  
    14.         // 接收並列印客戶端的資訊
    15.         System.out.println("Client said:" + resultStr);  
    16.         // 釋放資源,這行很關鍵
    17.         result.release();  
    18.         // 向客戶端傳送訊息
    19.         String response = "hello client!";  
    20.         // 在當前場景下,傳送的資料必須轉換成ByteBuf陣列
    21.         ByteBuf encoded = ctx.alloc().buffer(4 * response.length());  
    22.         encoded.writeBytes(response.getBytes());  
    23.         ctx.write(encoded);  
    24.         ctx.flush();  
    25.     }  
    26.     @Override
    27.     publicvoid exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
    28.         // 當出現異常就關閉連線
    29.         cause.printStackTrace();  
    30.         ctx.close();  
    31.     }  
    32.     @Override
    33.     publicvoid channelReadComplete(ChannelHandlerContext ctx) throws Exception {  
    34.         ctx.flush();  
    35.     }  
    36. }  
     
  4. SimpleServer(客戶端)
    Java程式碼  收藏程式碼
    1. package com.yingjun.netty.server;  
    2. import io.netty.bootstrap.Bootstrap;  
    3. import io.netty.bootstrap.ServerBootstrap;  
    4. import io.netty.channel.ChannelFuture;  
    5. import io.netty.channel.ChannelInitializer;  
    6. import io.netty.channel.ChannelOption;  
    7. import io.netty.channel.EventLoopGroup;  
    8. import io.netty.channel.nio.NioEventLoopGroup;  
    9. import io.netty.channel.socket.SocketChannel;  
    10. import io.netty.channel.socket.nio.NioServerSocketChannel;  
    11. import io.netty.channel.socket.nio.NioSocketChannel;  
    12. publicclass SimpleClient {  
    13.     publicvoid connect(String host, int port) throws Exception {  
    14.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
    15.         try {  
    16.             Bootstrap b = new Bootstrap();  
    17.             b.group(workerGroup);  
    18.             b.channel(NioSocketChannel.class);  
    19.             b.option(ChannelOption.SO_KEEPALIVE, true);  
    20.             b.handler(new ChannelInitializer<SocketChannel>() {  
    21.                 @Override
    22.                 publicvoid initChannel(SocketChannel ch) throws Exception {  
    23.                     ch.pipeline().addLast(new SimpleClientHandler());  
    24.                 }  
    25.             });  
    26.             // Start the client.
    27.             ChannelFuture f = b.connect(host, port).sync();  
    28.             // Wait until the connection is closed.
    29.             f.channel().closeFuture().sync();  
    30.         } finally {  
    31.             workerGroup.shutdownGracefully();  
    32.         }  
    33.     }  
    34.     publicstaticvoid main(String[] args) throws Exception {  
    35.         SimpleClient client=new SimpleClient();  
    36.         client.connect("127.0.0.1"9999);  
    37.     }  
    38. }  
     
  5. SimpleServerHandler(客戶端請求處理Handler)
    Java程式碼  收藏程式碼
    1. package com.yingjun.netty.server;  
    2. import io.netty.buffer.ByteBuf;  
    3. import io.netty.channel.ChannelHandlerContext;  
    4. import io.netty.channel.ChannelInboundHandlerAdapter;  
    5. publicclass SimpleClientHandler extends ChannelInboundHandlerAdapter {  
    6.     @Override
    7.     publicvoid channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
    8.         System.out.println("SimpleClientHandler.channelRead");    
    9.         ByteBuf result = (ByteBuf) msg;    
    10.         byte[] result1 = newbyte[result.readableBytes()];    
    11.         result.readBytes(result1);    
    12.         System.out.println("Server said:" + new String(result1));    
    13.         result.release();    
    14.     }  
    15.     @Override
    16.     publicvoid exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
    17.         // 當出現異常就關閉連線
    18.         cause.printStackTrace();  
    19.         ctx.close();  
    20.     }  
    21.     // 連線成功後,向server傳送訊息  
    22.     @Override
    23.     publicvoid channelActive(ChannelHandlerContext ctx) throws Exception {    
    24.         String msg = "hello Server!";    
    25.         ByteBuf encoded = ctx.alloc().buffer(4 * msg.length());    
    26.         encoded.writeBytes(msg.getBytes());    
    27.         ctx.write(encoded);    
    28.         ctx.flush();    
    29.     }    
    30. }  
     
  6. 執行結果:

    Java程式碼  收藏程式碼
    1. SimpleClientHandler.channelRead  
    2. Server said:hello client!  
    3. ------------------------------------------  
    4. SimpleServerHandler.channelRead  
    5. Client said:hello Server!  
    6. SimpleServerHandler.channelRead  
    7. Client said:hello Server!