咱們可能都學過Socket通訊/io/nio/aio等的編程。若是想把Socket真正的用於實際工做中去,那麼還須要不斷的完善、擴展和優化。好比很經典的Tcp讀包寫包問題,或者是數據接收的大小,實際的通訊讀取與應答的處理邏輯等等。當細節問題須要咱們認真的去思考,而這些咱們都須要大量的時間和精力,以及豐富的經驗。html
因此想學好socket通訊不是件容易的事情。那麼如今,咱們就須要學習一門新的技術Netty。java
咱們爲何選擇Netty?緣由是它簡單。咱們不再須要去編寫複雜的代碼和邏輯去實現通訊;咱們不再須要去考慮性能問題;咱們不再須要考慮編解碼問題、半包讀寫等問題。這些強大的功能Netty已經幫咱們實現了,咱們只須要使用它便可!編程
Netty是目前最流行的NIO框架,它的健壯性、功能、性能、可定製性和可擴展性在同類框架中都是數一數二的。bootstrap
Netty已經獲得成百上千的商業/商用項目驗證,如Hadoop的RPC框架Avro、以及咱們以後學習的JMS框架,強大的RocketMQ、還有主流的分佈式通訊框架Dubbox等等。安全
Netty5廢棄的緣由
Netty5可能底層有一些小問題,可能版本更新太快了,而後他把Netty5起了一個分支叫Netty4.1。服務器
Netty架構圖網絡
Netty特性架構
設計:各類傳輸類型,阻塞和非阻塞的套接字統一的API使用靈活簡單但功能強大的線程模型無鏈接的DatagramSocket支持鏈邏輯,易於重用。框架
易於使用:提供大量的文檔例子,處理依賴JDK1.6+,沒有其餘任何的依賴關係,某些功能依賴JDK1.7+,其餘特定可能有相關依賴,但都是可選的!socket
性能:比Java APIS更好的吞吐量和更低的延遲,由於線程池和重用因此消耗較小的資源,儘可能減小沒必要要的內存拷貝。
健壯性:健壯性鏈接快或慢或超載不會致使更多的內存溢出錯誤,在高速的網絡環境中不會不公平的讀或寫
安全性:完整的SSL/TLS和StartTLS支持能夠在OSGI等的受限制的環境中運行。
社區:版本發佈頻繁,社區活躍。
對應Netty的介紹就到這裏,下面使用Netty框架實現一個HelloWorld。
第一步:下載Netty的jar包
這裏使用的是Netty4.1版本。官網下載地址:https://netty.io/downloads.html
第二步:新建java工程
一、新建一個java工程,按照下圖新建4個類
二、新建一個lib目錄並把Netty的jar包拷貝到該目錄
三、把jar包添加到環境變量
第三步:編寫ServerHandler類代碼,代碼以下
1 package netty.helloworld; 2 3 import io.netty.buffer.ByteBuf; 4 import io.netty.buffer.Unpooled; 5 import io.netty.channel.ChannelHandlerContext; 6 import io.netty.channel.ChannelInboundHandlerAdapter; 7 8 public class ServerHandler extends ChannelInboundHandlerAdapter { 9 @Override 10 public void channelActive(ChannelHandlerContext ctx) throws Exception { 11 System.out.println("server channel active... "); 12 } 13 14 @Override 15 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 16 ByteBuf buf = (ByteBuf) msg; 17 byte[] req = new byte[buf.readableBytes()]; 18 buf.readBytes(req); 19 String body = new String(req, "utf-8"); 20 System.out.println("Server :" + body ); 21 String response = "進行返回給客戶端的響應:" + body; 22 ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes())); 23 } 24 25 @Override 26 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 27 System.out.println("讀完了"); 28 ctx.flush(); 29 } 30 31 @Override 32 public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception { 33 ctx.close(); 34 } 35 }
第四步:編寫Server類代碼,代碼以下
1 package netty.helloworld; 2 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 12 public class Server { 13 public static void main(String[] args) throws Exception { 14 // 1 建立線兩個程組 15 // 一個是用於處理服務器端接收客戶端鏈接的 16 // 一個是進行網絡通訊的(網絡讀寫的) 17 EventLoopGroup pGroup = new NioEventLoopGroup(); 18 EventLoopGroup cGroup = new NioEventLoopGroup(); 19 20 // 2 建立輔助工具類,用於服務器通道的一系列配置 21 ServerBootstrap b = new ServerBootstrap(); 22 b.group(pGroup, cGroup) // 綁定倆個線程組 23 .channel(NioServerSocketChannel.class) // 指定NIO的模式 24 .option(ChannelOption.SO_BACKLOG, 1024) // 設置tcp緩衝區 25 .option(ChannelOption.SO_SNDBUF, 32*1024) // 設置發送緩衝大小 26 .option(ChannelOption.SO_RCVBUF, 32*1024) // 這是接收緩衝大小 27 .option(ChannelOption.SO_KEEPALIVE, true) // 保持鏈接 28 .childHandler(new ChannelInitializer<SocketChannel>() { 29 @Override 30 protected void initChannel(SocketChannel sc) throws Exception { 31 // 3 在這裏配置具體數據接收方法的處理 32 sc.pipeline().addLast(new ServerHandler()); 33 } 34 }); 35 36 // 4 進行綁定 37 ChannelFuture cf1 = b.bind(8888).sync(); 38 // 5 等待關閉 39 cf1.channel().closeFuture().sync(); 40 pGroup.shutdownGracefully(); 41 cGroup.shutdownGracefully(); 42 } 43 }
第五步:編寫ClientHandler類代碼,代碼以下
1 package netty.helloworld; 2 3 import io.netty.buffer.ByteBuf; 4 import io.netty.channel.ChannelHandlerContext; 5 import io.netty.channel.ChannelInboundHandlerAdapter; 6 import io.netty.util.ReferenceCountUtil; 7 8 public class ClientHandler extends ChannelInboundHandlerAdapter { 9 @Override 10 public void channelActive(ChannelHandlerContext ctx) throws Exception {} 11 12 @Override 13 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 14 try { 15 ByteBuf buf = (ByteBuf) msg; 16 17 byte[] req = new byte[buf.readableBytes()]; 18 buf.readBytes(req); 19 20 String body = new String(req, "utf-8"); 21 System.out.println("Client :" + body ); 22 } finally { 23 ReferenceCountUtil.release(msg); 24 } 25 } 26 27 @Override 28 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {} 29 30 @Override 31 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 32 ctx.close(); 33 } 34 }
第六步:編寫Client類代碼,代碼以下
1 package netty.helloworld; 2 3 import io.netty.bootstrap.Bootstrap; 4 import io.netty.buffer.Unpooled; 5 import io.netty.channel.ChannelFuture; 6 import io.netty.channel.ChannelInitializer; 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.NioSocketChannel; 11 12 public class Client { 13 public static void main(String[] args) throws Exception{ 14 EventLoopGroup group = new NioEventLoopGroup(); 15 Bootstrap b = new Bootstrap(); 16 b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() { 17 @Override 18 protected void initChannel(SocketChannel sc) throws Exception { 19 sc.pipeline().addLast(new ClientHandler()); 20 } 21 }); 22 23 ChannelFuture cf1 = b.connect("127.0.0.1", 8888).syncUninterruptibly(); 24 // 發送消息 25 byte[] msg = "發送第1條測試消息".getBytes(); 26 cf1.channel().writeAndFlush(Unpooled.copiedBuffer(msg)); 27 28 // 等待關閉 29 cf1.channel().closeFuture().sync(); 30 group.shutdownGracefully(); 31 } 32 }
第七步:啓動Server服務
最後一步:啓動客戶端
控制檯輸出
關於Netty框架學習的第一節課就講到這裏,其餘更多關於Netty方面的教程後續會陸續更新!!
end -- 1346ac475e98aed
須要索取完整源碼或者其餘任何有關技術問題和疑問,直接wxhaox