日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Netty(二)——TCP粘包/拆包

發布時間:2024/4/14 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Netty(二)——TCP粘包/拆包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請注明出處:http://www.cnblogs.com/Joanna-Yan/p/7814644.html?

前面講到:Netty(一)——Netty入門程序

主要內容:

  • TCP粘包/拆包的基礎知識
  • 沒考慮TCP粘包/拆包的問題案例
  • 使用Netty解決讀半包問題

1.TCP粘包/拆包

  TCP是個“流”協議,所謂流,就是沒有界限的一串數據。TCP底層并不了解上層業務數據的具體含義,它會根據TCP緩沖區的實際情況進行包的劃分,所以在業務上認為,一個完整的包可能會被TCP拆分成多個包進行發送,也有可能把多個小的包封裝成一個大的數據包發送,這就是所謂的TCP粘包和拆包的問題。

1.1 TCP粘包/拆包問題說明

 我們通過下圖對TCP粘包和拆包問題進行說明:

  假設客戶端分別發送了兩個數據包D1和D2給服務端,由于服務端一次讀取到的字節數是不確定的,故可能存在以下四種情況。

  • 服務端分兩次讀取到了兩個獨立的數據包,分別是D1和D2,沒有粘包和拆包;
  • 服務端一次接收到了兩個數據包,D1和D2粘合在一起,被稱為TCP粘包;
  • 服務端分兩次讀取到了兩個數據包,第一次讀取到了完整的D1包和D2包的部分內容,第二次讀取到了D2包的剩余內容,這被稱為TCP拆包;
  • 服務端分兩次讀取到了兩個數據包,第一次讀取到了D1包的部分內容D1_1,第二次讀取到了D1包的剩余內容D1_2和D2包的整包。
  •   如果此時服務端TCP接收滑窗非常小,而數據包D1和D2比較大,很可能會發生第五種可能,即服務端分多次才能將D1和D2包接收完全,期間發生多次拆包。

    1.2 TCP粘包/拆包發生的原因

      問題產生的原因有三個:

  • 應用程序write寫入的字節大小大于套接字發送緩存區大小;
  • 進行MSS大小的TCP分段;
  • 以太網幀的payload大于MTU進行IP分片。
  • 1.3 粘包問題的解決策略

      由于底層的TCP無法理解上層的業務數據,所以在底層是無法保證數據包不被拆分和重組的,這個問題只能通過上層的應用協議棧設計來解決,根據業界的主流協議的解決方案,可以歸納如下。

  • 消息定長,例如每個報文的大小和固定長度200字節,如果不夠,空位補空格;
  • 在包尾增加回車換行符進行分割,例如FTP協議;
  • 將消息分為消息頭和消息體,消息頭中包含表示消息總長度(或者消息體長度)的字段,通常設計思路為消息頭的第一個字段使用int32來表示消息的總長度;
  • 更復雜的應用層協議。
  •   下面我們就通過實際示例來看看如何使用Netty提供的半包解碼器來解決TCP粘包/拆包問題。

    2.未考慮TCP粘包導致功能異常案例

      在前面的時間服務器示例中,我們多次強調并沒有考慮讀半包問題,這在功能測試時往往沒有問題,但是一旦壓力上來,或者發送大報文之后,就會存在粘包/拆包問題。如果代碼沒有考慮,往往就會出現解碼錯位或者錯誤,導致程序不能正常工作。下面我們以前面的Netty(一)——Netty入門程序為例,模擬故障場景,然后看看如何正確使用Netty的半包解碼器來解決TCP粘包/拆包問題。

    2.1TimeServer的改造

    package joanna.yan.netty;import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; 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 TimeServer {public static void main(String[] args) throws Exception {int port=9090;if(args!=null&&args.length>0){try {port=Integer.valueOf(args[0]);} catch (Exception e) {// 采用默認值 }}new TimeServer().bind(port);}public void bind(int port) throws Exception{/** 配置服務端的NIO線程組,它包含了一組NIO線程,專門用于網絡事件的處理,實際上它們就是Reactor線程組。* 這里創建兩個的原因:一個用于服務端接受客戶端的連接,* 另一個用于進行SocketChannel的網絡讀寫。*/EventLoopGroup bossGroup=new NioEventLoopGroup();EventLoopGroup workerGroup=new NioEventLoopGroup();try {//ServerBootstrap對象,Netty用于啟動NIO服務端的輔助啟動類,目的是降低服務端的開發復雜度。ServerBootstrap b=new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)/** 綁定I/O事件的處理類ChildChannelHandler,它的作用類似于Reactor模式中的handler類,* 主要用于處理網絡I/O事件,例如:記錄日志、對消息進行編解碼等。*/.childHandler(new ChildChannelHandler());/** 綁定端口,同步等待成功(調用它的bind方法綁定監聽端口,隨后,調用它的同步阻塞方法sync等待綁定操作完成。* 完成之后Netty會返回一個ChannelFuture,它的功能類似于JDK的java.util.concurrent.Future,* 主要用于異步操作的通知回調。)*/ChannelFuture f=b.bind(port).sync();//等待服務端監聽端口關閉(使用f.channel().closeFuture().sync()方法進行阻塞,等待服務端鏈路關閉之后main函數才退出。) f.channel().closeFuture().sync();}finally{//優雅退出,釋放線程池資源 bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{@Overrideprotected void initChannel(SocketChannel arg0) throws Exception { // arg0.pipeline().addLast(new TimeServerHandler());//模擬粘包/拆包故障場景arg0.pipeline().addLast(new TimeServerHandler1());}} } import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;/*** 用于對網絡事件進行讀寫操作* 模擬粘包/拆包故障場景* @author Joanna.Yan* @date 2017年11月8日下午6:54:35*/ public class TimeServerHandler1 extends ChannelInboundHandlerAdapter{private int counter;@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception {ByteBuf buf=(ByteBuf) msg;byte[] req=new byte[buf.readableBytes()];buf.readBytes(req);String body=new String(req, "UTF-8").substring(0, req.length-System.getProperty("line.separator").length());System.out.println("The time server receive order : "+body+" ;the counter is :"+ ++counter);String currentTime="QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";currentTime=currentTime+System.getProperty("line.separator"); ByteBuf resp=Unpooled.copiedBuffer(currentTime.getBytes());ctx.write(resp);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {ctx.close();} }

    2.2TimeClient的改造

    package joanna.yan.netty;import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; 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 TimeClient {public static void main(String[] args) throws Exception {int port=9090;if(args!=null&&args.length>0){try {port=Integer.valueOf(args[0]);} catch (Exception e) {// 采用默認值 }}new TimeClient().connect(port, "127.0.0.1");}public void connect(int port,String host) throws Exception{//配置客戶端NIO線程組EventLoopGroup group=new NioEventLoopGroup();try {Bootstrap b=new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception { // ch.pipeline().addLast(new TimeClientHandler());//模擬粘包/拆包故障場景ch.pipeline().addLast(new TimeClientHandler1());}});//發起異步連接操作ChannelFuture f=b.connect(host, port).sync();//等待客戶端鏈路關閉 f.channel().closeFuture().sync();}finally{//優雅退出,釋放NIO線程組 group.shutdownGracefully();}} } package joanna.yan.netty;import java.util.logging.Logger; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; /*** 模擬粘包/拆包故障場景* @author Joanna.Yan* @date 2017年11月10日下午2:18:51*/ public class TimeClientHandler1 extends ChannelInboundHandlerAdapter{private static final Logger logger=Logger.getLogger(TimeClientHandler1.class.getName());private int counter;private byte[] req;public TimeClientHandler1(){req=("QUER TIME ORDER"+System.getProperty("line.separator")).getBytes();}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {ByteBuf message=null;for (int i = 0; i < 100; i++) {message=Unpooled.buffer(req.length);message.writeBytes(req);ctx.writeAndFlush(message);}}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception {ByteBuf buf=(ByteBuf) msg;byte[] req=new byte[buf.readableBytes()];buf.readBytes(req);String body=new String(req, "UTF-8");System.out.println("Now is :"+body+" ;the counter is :" + ++counter);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {//釋放資源logger.warning("Unexpected exception from downstream : "+cause.getMessage());ctx.close();} }

    2.3運行結果

      分別執行服務端和客戶端,運行結果如下:

      服務端運行結果如下:

    The time server receive order : QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QU ;the counter is :1 The time server receive order : TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER QUER TIME ORDER ;the counter is :2 View Code

      服務端運行結果表明它只接收到了兩條消息,總數正好是100條,我們期待的是收到100條消息,每條包括一條“QUERY TIME ORDER”指令。這說明發生了TCP粘包。

      客戶端運行結果如下:

    Now is : BAD ORDER BAD ORDER ; the counter is : 1

      按照設計初衷,客戶端應該收到100條當前系統時間的消息,但實際上只收到了一條。這不難理解,因為服務端只收到了2條請求消息,所以實際服務端只發送了2條應答,由于請求消息不滿足查詢條件,所以只返回了2條“BAD ORDER”應答消息。但是實際上客戶端只收到了一條包含2條“BAD ORDER”指令的消息,說明服務端返回的應答消息也發送了粘包。

      由于上面的例程沒有考慮TCP的粘包/拆包,所以當發生TCP粘包時,我們的程序就不能正常工作。

      下面我們通過Netty的LineBaseFrameDecoder和StringDecoder來解決TCP粘包問題。

    3.利用LineBasedFrameDecoder解決TCP粘包問題

      為了解決TCP粘包/拆包導致的半包讀寫問題,Netty默認提供了多種編解碼器用于處理半包,只要能熟練掌握這些類庫的使用,TCP粘包問題從此會變得非常容易,你甚至不需要關心它們,這也是其他NIO框架和JDK原生的NIO API所無法匹敵的。

      下面我們對時間服務進行修改。

    3.1支持TCP粘包的TimeServer

    package joanna.yan.netty.sp;import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder;public class TimeServer {public static void main(String[] args) throws Exception {int port=9090;if(args!=null&&args.length>0){try {port=Integer.valueOf(args[0]);} catch (Exception e) {// 采用默認值 }}new TimeServer().bind(port);}public void bind(int port) throws Exception{//配置服務端的NIO線程組EventLoopGroup bossGroup=new NioEventLoopGroup();EventLoopGroup workerGroup=new NioEventLoopGroup();try {ServerBootstrap b=new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChildChannelHandler());//綁定端口,同步等待成功ChannelFuture f=b.bind(port).sync();//等待服務端監聽端口關閉 f.channel().closeFuture().sync();}finally{//優雅退出,釋放線程池資源 bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{@Overrideprotected void initChannel(SocketChannel arg0) throws Exception {arg0.pipeline().addLast(new LineBasedFrameDecoder(1024));arg0.pipeline().addLast(new StringDecoder());arg0.pipeline().addLast(new TimeServerHandler());} } } package joanna.yan.netty.sp;import java.util.Date; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;public class TimeServerHandler extends ChannelInboundHandlerAdapter{private int counter;@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception {String body=(String) msg;System.out.println("The time server receive order : "+body+" ;the counter is : "+ ++counter);String currentTime="QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";currentTime =currentTime+System.getProperty("line.separator"); ByteBuf resp=Unpooled.copiedBuffer(currentTime.getBytes());ctx.writeAndFlush(resp);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {ctx.close();}}

    3.2支持TCP粘包的TimeClient

    package joanna.yan.netty.sp;import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.LineBasedFrameDecoder; import io.netty.handler.codec.string.StringDecoder;public class TimeClient {public static void main(String[] args) throws Exception {int port=9090;if(args!=null&&args.length>0){try {port=Integer.valueOf(args[0]);} catch (Exception e) {// 采用默認值 }}new TimeClient().connect(port, "127.0.0.1");}public void connect(int port,String host) throws Exception{//配置客戶端NIO線程組EventLoopGroup group=new NioEventLoopGroup();try {Bootstrap b=new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {//直接在TimeClientHandler之前新增LineBasedFrameDecoder和StringDecoder解碼器ch.pipeline().addLast(new LineBasedFrameDecoder(1024));ch.pipeline().addLast(new StringDecoder());ch.pipeline().addLast(new TimeClientHandler());}});//發起異步連接操作ChannelFuture f=b.connect(host, port).sync();//等待客戶端鏈路關閉 f.channel().closeFuture().sync();}finally{//優雅退出,釋放NIO線程組 group.shutdownGracefully();}} } package joanna.yan.netty.sp;import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import java.util.logging.Logger;public class TimeClientHandler extends ChannelInboundHandlerAdapter{private static final Logger logger=Logger.getLogger(TimeClientHandler.class.getName());private int counter;private byte[] req;public TimeClientHandler(){req=("QUERY TIME ORDER"+System.getProperty("line.separator")).getBytes();}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {ByteBuf message=null;for (int i = 0; i < 100; i++) {message=Unpooled.buffer(req.length);message.writeBytes(req);ctx.writeAndFlush(message);}}@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception {//拿到的msg已經是解碼成字符串之后的應答消息了,相比于之前的代碼簡潔明了很多。String body=(String) msg;System.out.println("Now is :"+body+" ;the counter is :" + ++counter);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {//釋放資源logger.warning("Unexpected exception from downstream : "+cause.getMessage());ctx.close();} }

    3.3運行支持TCP粘包的時間服務器程序

      為了盡量模擬TCP粘包和半包場景,采用簡單的壓力測試,鏈路建立成功之后,客戶端連續發送100條消息給服務端,然后查看服務端和客戶端的運行結果。

      服務端執行結果如下:

    The time server receive order : QUER TIME ORDER ;the counter is : 1 The time server receive order : QUER TIME ORDER ;the counter is : 2 The time server receive order : QUER TIME ORDER ;the counter is : 3 The time server receive order : QUER TIME ORDER ;the counter is : 4 The time server receive order : QUER TIME ORDER ;the counter is : 5 The time server receive order : QUER TIME ORDER ;the counter is : 6 The time server receive order : QUER TIME ORDER ;the counter is : 7 The time server receive order : QUER TIME ORDER ;the counter is : 8 The time server receive order : QUER TIME ORDER ;the counter is : 9 The time server receive order : QUER TIME ORDER ;the counter is : 10 The time server receive order : QUER TIME ORDER ;the counter is : 11 The time server receive order : QUER TIME ORDER ;the counter is : 12 The time server receive order : QUER TIME ORDER ;the counter is : 13 The time server receive order : QUER TIME ORDER ;the counter is : 14 The time server receive order : QUER TIME ORDER ;the counter is : 15 The time server receive order : QUER TIME ORDER ;the counter is : 16 The time server receive order : QUER TIME ORDER ;the counter is : 17 The time server receive order : QUER TIME ORDER ;the counter is : 18 The time server receive order : QUER TIME ORDER ;the counter is : 19 The time server receive order : QUER TIME ORDER ;the counter is : 20 The time server receive order : QUER TIME ORDER ;the counter is : 21 The time server receive order : QUER TIME ORDER ;the counter is : 22 The time server receive order : QUER TIME ORDER ;the counter is : 23 The time server receive order : QUER TIME ORDER ;the counter is : 24 The time server receive order : QUER TIME ORDER ;the counter is : 25 The time server receive order : QUER TIME ORDER ;the counter is : 26 The time server receive order : QUER TIME ORDER ;the counter is : 27 The time server receive order : QUER TIME ORDER ;the counter is : 28 The time server receive order : QUER TIME ORDER ;the counter is : 29 The time server receive order : QUER TIME ORDER ;the counter is : 30 The time server receive order : QUER TIME ORDER ;the counter is : 31 The time server receive order : QUER TIME ORDER ;the counter is : 32 The time server receive order : QUER TIME ORDER ;the counter is : 33 The time server receive order : QUER TIME ORDER ;the counter is : 34 The time server receive order : QUER TIME ORDER ;the counter is : 35 The time server receive order : QUER TIME ORDER ;the counter is : 36 The time server receive order : QUER TIME ORDER ;the counter is : 37 The time server receive order : QUER TIME ORDER ;the counter is : 38 The time server receive order : QUER TIME ORDER ;the counter is : 39 The time server receive order : QUER TIME ORDER ;the counter is : 40 The time server receive order : QUER TIME ORDER ;the counter is : 41 The time server receive order : QUER TIME ORDER ;the counter is : 42 The time server receive order : QUER TIME ORDER ;the counter is : 43 The time server receive order : QUER TIME ORDER ;the counter is : 44 The time server receive order : QUER TIME ORDER ;the counter is : 45 The time server receive order : QUER TIME ORDER ;the counter is : 46 The time server receive order : QUER TIME ORDER ;the counter is : 47 The time server receive order : QUER TIME ORDER ;the counter is : 48 The time server receive order : QUER TIME ORDER ;the counter is : 49 The time server receive order : QUER TIME ORDER ;the counter is : 50 The time server receive order : QUER TIME ORDER ;the counter is : 51 The time server receive order : QUER TIME ORDER ;the counter is : 52 The time server receive order : QUER TIME ORDER ;the counter is : 53 The time server receive order : QUER TIME ORDER ;the counter is : 54 The time server receive order : QUER TIME ORDER ;the counter is : 55 The time server receive order : QUER TIME ORDER ;the counter is : 56 The time server receive order : QUER TIME ORDER ;the counter is : 57 The time server receive order : QUER TIME ORDER ;the counter is : 58 The time server receive order : QUER TIME ORDER ;the counter is : 59 The time server receive order : QUER TIME ORDER ;the counter is : 60 The time server receive order : QUER TIME ORDER ;the counter is : 61 The time server receive order : QUER TIME ORDER ;the counter is : 62 The time server receive order : QUER TIME ORDER ;the counter is : 63 The time server receive order : QUER TIME ORDER ;the counter is : 64 The time server receive order : QUER TIME ORDER ;the counter is : 65 The time server receive order : QUER TIME ORDER ;the counter is : 66 The time server receive order : QUER TIME ORDER ;the counter is : 67 The time server receive order : QUER TIME ORDER ;the counter is : 68 The time server receive order : QUER TIME ORDER ;the counter is : 69 The time server receive order : QUER TIME ORDER ;the counter is : 70 The time server receive order : QUER TIME ORDER ;the counter is : 71 The time server receive order : QUER TIME ORDER ;the counter is : 72 The time server receive order : QUER TIME ORDER ;the counter is : 73 The time server receive order : QUER TIME ORDER ;the counter is : 74 The time server receive order : QUER TIME ORDER ;the counter is : 75 The time server receive order : QUER TIME ORDER ;the counter is : 76 The time server receive order : QUER TIME ORDER ;the counter is : 77 The time server receive order : QUER TIME ORDER ;the counter is : 78 The time server receive order : QUER TIME ORDER ;the counter is : 79 The time server receive order : QUER TIME ORDER ;the counter is : 80 The time server receive order : QUER TIME ORDER ;the counter is : 81 The time server receive order : QUER TIME ORDER ;the counter is : 82 The time server receive order : QUER TIME ORDER ;the counter is : 83 The time server receive order : QUER TIME ORDER ;the counter is : 84 The time server receive order : QUER TIME ORDER ;the counter is : 85 The time server receive order : QUER TIME ORDER ;the counter is : 86 The time server receive order : QUER TIME ORDER ;the counter is : 87 The time server receive order : QUER TIME ORDER ;the counter is : 88 The time server receive order : QUER TIME ORDER ;the counter is : 89 The time server receive order : QUER TIME ORDER ;the counter is : 90 The time server receive order : QUER TIME ORDER ;the counter is : 91 The time server receive order : QUER TIME ORDER ;the counter is : 92 The time server receive order : QUER TIME ORDER ;the counter is : 93 The time server receive order : QUER TIME ORDER ;the counter is : 94 The time server receive order : QUER TIME ORDER ;the counter is : 95 The time server receive order : QUER TIME ORDER ;the counter is : 96 The time server receive order : QUER TIME ORDER ;the counter is : 97 The time server receive order : QUER TIME ORDER ;the counter is : 98 The time server receive order : QUER TIME ORDER ;the counter is : 99 The time server receive order : QUER TIME ORDER ;the counter is : 100 View Code

      客戶端執行結果如下:

    Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :1 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :2 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :3 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :4 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :5 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :6 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :7 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :8 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :9 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :10 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :11 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :12 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :13 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :14 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :15 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :16 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :17 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :18 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :19 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :20 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :21 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :22 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :23 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :24 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :25 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :26 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :27 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :28 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :29 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :30 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :31 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :32 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :33 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :34 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :35 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :36 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :37 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :38 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :39 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :40 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :41 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :42 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :43 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :44 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :45 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :46 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :47 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :48 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :49 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :50 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :51 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :52 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :53 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :54 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :55 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :56 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :57 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :58 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :59 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :60 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :61 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :62 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :63 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :64 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :65 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :66 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :67 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :68 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :69 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :70 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :71 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :72 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :73 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :74 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :75 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :76 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :77 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :78 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :79 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :80 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :81 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :82 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :83 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :84 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :85 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :86 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :87 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :88 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :89 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :90 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :91 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :92 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :93 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :94 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :95 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :96 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :97 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :98 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :99 Now is :Wed Aug 30 16:38:34 CST 2017 ;the counter is :100 View Code

      程序的運行結果完全符合預期,說明通過使用LineBasedFrameDecoder和StringDecoder成功解決了TCP粘包導致的讀半包問題。對于使用者來說,只要將支持半包解碼的handler添加到ChannelPipeline中即可,不需要寫額外的代碼,用戶使用起來非常簡單。

    3.4?LineBasedFrameDecoder和StringDecoder原理分析

      LineBasedFrameDecoder的工作原理是它依次遍歷ByteBuf中的可讀字節,判斷看是否有"\n"或者“\r\n”,如果有,就以此位置為結束位置,從可讀索引到結束位置區間的字節就組成了一行。它是以換行符為結束標志的解碼器,支持攜帶結束符或者不攜帶結束符兩種解碼方式。同時支持配置單行的最大長度。如果連續讀取到的最大長度后仍沒有發現換行符,就會拋出異常,同時忽略掉之前督導的異常碼流。

      StringDecoder的功能非常簡單,就是將收到到的對象轉換成字符串,然后繼續調用后面的handler。LineBasedFrameDecoder+StringDecoder組合就是按行切換的文本解碼器,它被設計用來支持TCP的粘包和拆包。

      疑問:如果發送的消息不是以換行符結束的該怎么辦呢?或者沒有回車換行符,靠消息頭中的長度字段來分包怎么辦?是不是需要自己寫半包解碼器?答案是否定的,Netty提供了多種支持TCP粘包/拆包的解碼器,用來滿足用戶的不同訴求。

    如果此文對您有幫助,微信打賞我一下吧~

    ?

    轉載于:https://www.cnblogs.com/Joanna-Yan/p/7814644.html

    超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

    總結

    以上是生活随笔為你收集整理的Netty(二)——TCP粘包/拆包的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。