【Netty】TCP粘包和拆包
一、前言
前面已經(jīng)基本上講解完了Netty的主要內(nèi)容,現(xiàn)在來(lái)學(xué)習(xí)Netty中的一些可能存在的問(wèn)題,如TCP粘包和拆包。
二、粘包和拆包
對(duì)于TCP協(xié)議而言,當(dāng)?shù)讓影l(fā)送消息和接受消息時(shí),都需要考慮TCP的粘包和拆包問(wèn)題,一個(gè)完整的數(shù)據(jù)包可能會(huì)被TCP拆分為多個(gè)包發(fā)送,或者將多個(gè)小的數(shù)據(jù)包封裝成大的數(shù)據(jù)包發(fā)送。
2.1 粘包和拆包基礎(chǔ)
假設(shè)客戶(hù)端發(fā)送D1和D2兩個(gè)數(shù)據(jù)包至服務(wù)端,由于服務(wù)端每次讀取的數(shù)據(jù)大小時(shí)不確定的,因此,可能存在如下四種情況。
?
① 服務(wù)端分兩次讀取到數(shù)據(jù)包,分別為D1和D2,沒(méi)有粘包和拆包。
② 服務(wù)端一次讀取兩個(gè)數(shù)據(jù)包D1和D2,D1和D2黏合在一起,稱(chēng)為T(mén)CP粘包。
③ 服務(wù)端一次讀取完整的D1數(shù)據(jù)包和D2數(shù)據(jù)包的一部分,第二次讀取D2剩余的部分,稱(chēng)為T(mén)CP拆包。
④ 服務(wù)端一次讀取D1數(shù)據(jù)包的一部分,第二次讀取D1的剩余部分和D2數(shù)據(jù)包。
可以看到,在底層發(fā)送數(shù)據(jù)時(shí),可能會(huì)發(fā)生粘包和拆包,其原因大致有如下三種。
① 應(yīng)用程序?qū)懭胱止?jié)大小大于套接字緩沖區(qū)大小。
② 進(jìn)行MSS(Max Segment Size)大小的TCP分段。
③ 以太網(wǎng)幀的負(fù)載大于MTU(Maximum Transmission Unit)進(jìn)行分片。
由于底層的TCP協(xié)議無(wú)法理解上層的業(yè)務(wù)數(shù)據(jù),所以底層無(wú)法保證數(shù)據(jù)不被拆分和重組,而為了解決粘包問(wèn)題,業(yè)界主要的策略如下。
① 消息定長(zhǎng),如每個(gè)報(bào)文大小固定為200個(gè)字節(jié),如果不夠,空格補(bǔ)位。
② 在包尾添加回車(chē)換行符進(jìn)行分割,如FTP協(xié)議。
③ 將消息劃分為消息頭和消息體,消息頭中包含消息總長(zhǎng)度的字段。
2.2 TCP粘包示例
下面通過(guò)一個(gè)示例展示未考慮粘包問(wèn)題導(dǎo)致的異常。
1. TimeServerHandler
package com.hust.grid.leesf.chapter4;import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;/*** Created by Leesf on 2017/6/28.*/ public class TimeServerHandler 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 java.util.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) {cause.printStackTrace();ctx.close();} }2. TimeServer
package com.hust.grid.leesf.chapter4;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;/*** Created by Leesf on 2017/6/28.*/public class TimeServer {public void bind(int port) throws Exception {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 TimeServerHandler());}}public static void main(String[] args) throws Exception {int port = 8080;if (args != null && args.length > 0) {try {port = Integer.valueOf(args[0]);} catch (NumberFormatException e) {// ignore }}new TimeServer().bind(port);} }3. TimeClientHandler
package com.hust.grid.leesf.chapter4;import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;import java.util.logging.Logger;/*** Created by Leesf on 2017/6/28.*/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) {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) {cause.printStackTrace();ctx.close();} }4. TimeClient
package com.hust.grid.leesf.chapter4;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;/*** Created by Leesf on 2017/6/28.*/public class TimeClient {public void connect(int port, String host) throws Exception {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch)throws Exception {ch.pipeline().addLast(new TimeClientHandler());}});ChannelFuture f = b.connect(host, port).sync();f.channel().closeFuture().sync();} finally {group.shutdownGracefully();}}public static void main(String[] args) throws Exception {int port = 8080;if (args != null && args.length > 0) {try {port = Integer.valueOf(args[0]);} catch (NumberFormatException e) {// ignore }}new TimeClient().connect(port, "127.0.0.1");} }分別運(yùn)行服務(wù)器和客戶(hù)端,其中服務(wù)器的運(yùn)行結(jié)果如下:
The time server receive order : QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORD ; the counter is : 1 The time server receive order : QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER QUERY TIME ORDER ; the counter is : 2 View Code客戶(hù)端的運(yùn)行結(jié)果如下:
Now is : BAD ORDER BAD ORDER; the counter is : 1可以看到服務(wù)端只接收到了兩條消息,一條消息包含了57條指令,另一條包含了43條指令,其與我們?cè)O(shè)計(jì)的100條單獨(dú)的消息不相符,發(fā)生了粘包。對(duì)于客戶(hù)端而言,其收到了兩條BAD ORDER,表示收到了兩條消息,counter應(yīng)該為2,但是其counter為1,表示也發(fā)生了粘包。
下面通過(guò)Netty的LineBasedFrameDecoder和String來(lái)解決粘包問(wèn)題。
1. TimeServerHandler
package com.hust.grid.leesf.chapter4.fault;import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;/*** Created by Leesf on 2017/6/28.*/ public class TimeServerHandler 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 java.util.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) {cause.printStackTrace();ctx.close();} }2. TimeServer
package com.hust.grid.leesf.chapter4.fault;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;/*** Created by Leesf on 2017/6/28.*/public class TimeServer {public void bind(int port) throws Exception {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 TimeServerHandler());}}public static void main(String[] args) throws Exception {int port = 8080;if (args != null && args.length > 0) {try {port = Integer.valueOf(args[0]);} catch (NumberFormatException e) {// ignore }}new TimeServer().bind(port);} }3. TimeClientHandler
package com.hust.grid.leesf.chapter4.correct;import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter;import java.util.logging.Logger;/*** Created by Leesf on 2017/6/28.*/ public class TimeClientHandler extends ChannelInboundHandlerAdapter {private int counter;private byte[] req;public TimeClientHandler() {req = ("QUERY TIME ORDER" + System.getProperty("line.separator")).getBytes();}@Overridepublic void channelActive(ChannelHandlerContext ctx) {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 {String body = (String) msg;System.out.println("Now is : " + body + " ; the counter is : "+ ++counter);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {cause.printStackTrace();ctx.close();} }4. TimeClient
package com.hust.grid.leesf.chapter4.correct;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;/*** Created by Leesf on 2017/6/28.*/public class TimeClient {public void connect(int port, String host) throws Exception {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch)throws Exception {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 {group.shutdownGracefully();}}public static void main(String[] args) throws Exception {int port = 8080;if (args != null && args.length > 0) {try {port = Integer.valueOf(args[0]);} catch (NumberFormatException e) {// ignore }}new TimeClient().connect(port, "127.0.0.1");} }分別運(yùn)行服務(wù)端和客戶(hù)端,服務(wù)端結(jié)果如下:
"D:\Program Files (x86)\Java\jdk1.8.0_65\bin\java" "-javaagent:D:\Program Files (x86)\JetBrains\IntelliJ IDEA 2017.1.4\lib\idea_rt.jar=62564:D:\Program Files (x86)\JetBrains\IntelliJ IDEA 2017.1.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\charsets.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\deploy.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\access-bridge-64.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\cldrdata.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\dnsns.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\jaccess.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\jfxrt.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\localedata.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\nashorn.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\sunec.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\sunjce_provider.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\sunmscapi.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\sunpkcs11.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\zipfs.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\javaws.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\jce.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\jfr.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\jfxswt.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\jsse.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\management-agent.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\plugin.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\resources.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\rt.jar;F:\01_Code\02_Idea\CoreInNetty\target\classes;C:\Users\lsf\.m2\repository\io\netty\netty-all\4.0.32.Final\netty-all-4.0.32.Final.jar;C:\Users\lsf\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.6.3\jackson-core-2.6.3.jar;C:\Users\lsf\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.6.3\jackson-databind-2.6.3.jar;C:\Users\lsf\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.6.0\jackson-annotations-2.6.0.jar" com.hust.grid.leesf.chapter4.correct.TimeServer The time server receive order : QUERY TIME ORDER ; the counter is : 1 The time server receive order : QUERY TIME ORDER ; the counter is : 2 The time server receive order : QUERY TIME ORDER ; the counter is : 3 The time server receive order : QUERY TIME ORDER ; the counter is : 4 The time server receive order : QUERY TIME ORDER ; the counter is : 5 The time server receive order : QUERY TIME ORDER ; the counter is : 6 The time server receive order : QUERY TIME ORDER ; the counter is : 7 The time server receive order : QUERY TIME ORDER ; the counter is : 8 The time server receive order : QUERY TIME ORDER ; the counter is : 9 The time server receive order : QUERY TIME ORDER ; the counter is : 10 The time server receive order : QUERY TIME ORDER ; the counter is : 11 The time server receive order : QUERY TIME ORDER ; the counter is : 12 The time server receive order : QUERY TIME ORDER ; the counter is : 13 The time server receive order : QUERY TIME ORDER ; the counter is : 14 The time server receive order : QUERY TIME ORDER ; the counter is : 15 The time server receive order : QUERY TIME ORDER ; the counter is : 16 The time server receive order : QUERY TIME ORDER ; the counter is : 17 The time server receive order : QUERY TIME ORDER ; the counter is : 18 The time server receive order : QUERY TIME ORDER ; the counter is : 19 The time server receive order : QUERY TIME ORDER ; the counter is : 20 The time server receive order : QUERY TIME ORDER ; the counter is : 21 The time server receive order : QUERY TIME ORDER ; the counter is : 22 The time server receive order : QUERY TIME ORDER ; the counter is : 23 The time server receive order : QUERY TIME ORDER ; the counter is : 24 The time server receive order : QUERY TIME ORDER ; the counter is : 25 The time server receive order : QUERY TIME ORDER ; the counter is : 26 The time server receive order : QUERY TIME ORDER ; the counter is : 27 The time server receive order : QUERY TIME ORDER ; the counter is : 28 The time server receive order : QUERY TIME ORDER ; the counter is : 29 The time server receive order : QUERY TIME ORDER ; the counter is : 30 The time server receive order : QUERY TIME ORDER ; the counter is : 31 The time server receive order : QUERY TIME ORDER ; the counter is : 32 The time server receive order : QUERY TIME ORDER ; the counter is : 33 The time server receive order : QUERY TIME ORDER ; the counter is : 34 The time server receive order : QUERY TIME ORDER ; the counter is : 35 The time server receive order : QUERY TIME ORDER ; the counter is : 36 The time server receive order : QUERY TIME ORDER ; the counter is : 37 The time server receive order : QUERY TIME ORDER ; the counter is : 38 The time server receive order : QUERY TIME ORDER ; the counter is : 39 The time server receive order : QUERY TIME ORDER ; the counter is : 40 The time server receive order : QUERY TIME ORDER ; the counter is : 41 The time server receive order : QUERY TIME ORDER ; the counter is : 42 The time server receive order : QUERY TIME ORDER ; the counter is : 43 The time server receive order : QUERY TIME ORDER ; the counter is : 44 The time server receive order : QUERY TIME ORDER ; the counter is : 45 The time server receive order : QUERY TIME ORDER ; the counter is : 46 The time server receive order : QUERY TIME ORDER ; the counter is : 47 The time server receive order : QUERY TIME ORDER ; the counter is : 48 The time server receive order : QUERY TIME ORDER ; the counter is : 49 The time server receive order : QUERY TIME ORDER ; the counter is : 50 The time server receive order : QUERY TIME ORDER ; the counter is : 51 The time server receive order : QUERY TIME ORDER ; the counter is : 52 The time server receive order : QUERY TIME ORDER ; the counter is : 53 The time server receive order : QUERY TIME ORDER ; the counter is : 54 The time server receive order : QUERY TIME ORDER ; the counter is : 55 The time server receive order : QUERY TIME ORDER ; the counter is : 56 The time server receive order : QUERY TIME ORDER ; the counter is : 57 The time server receive order : QUERY TIME ORDER ; the counter is : 58 The time server receive order : QUERY TIME ORDER ; the counter is : 59 The time server receive order : QUERY TIME ORDER ; the counter is : 60 The time server receive order : QUERY TIME ORDER ; the counter is : 61 The time server receive order : QUERY TIME ORDER ; the counter is : 62 The time server receive order : QUERY TIME ORDER ; the counter is : 63 The time server receive order : QUERY TIME ORDER ; the counter is : 64 The time server receive order : QUERY TIME ORDER ; the counter is : 65 The time server receive order : QUERY TIME ORDER ; the counter is : 66 The time server receive order : QUERY TIME ORDER ; the counter is : 67 The time server receive order : QUERY TIME ORDER ; the counter is : 68 The time server receive order : QUERY TIME ORDER ; the counter is : 69 The time server receive order : QUERY TIME ORDER ; the counter is : 70 The time server receive order : QUERY TIME ORDER ; the counter is : 71 The time server receive order : QUERY TIME ORDER ; the counter is : 72 The time server receive order : QUERY TIME ORDER ; the counter is : 73 The time server receive order : QUERY TIME ORDER ; the counter is : 74 The time server receive order : QUERY TIME ORDER ; the counter is : 75 The time server receive order : QUERY TIME ORDER ; the counter is : 76 The time server receive order : QUERY TIME ORDER ; the counter is : 77 The time server receive order : QUERY TIME ORDER ; the counter is : 78 The time server receive order : QUERY TIME ORDER ; the counter is : 79 The time server receive order : QUERY TIME ORDER ; the counter is : 80 The time server receive order : QUERY TIME ORDER ; the counter is : 81 The time server receive order : QUERY TIME ORDER ; the counter is : 82 The time server receive order : QUERY TIME ORDER ; the counter is : 83 The time server receive order : QUERY TIME ORDER ; the counter is : 84 The time server receive order : QUERY TIME ORDER ; the counter is : 85 The time server receive order : QUERY TIME ORDER ; the counter is : 86 The time server receive order : QUERY TIME ORDER ; the counter is : 87 The time server receive order : QUERY TIME ORDER ; the counter is : 88 The time server receive order : QUERY TIME ORDER ; the counter is : 89 The time server receive order : QUERY TIME ORDER ; the counter is : 90 The time server receive order : QUERY TIME ORDER ; the counter is : 91 The time server receive order : QUERY TIME ORDER ; the counter is : 92 The time server receive order : QUERY TIME ORDER ; the counter is : 93 The time server receive order : QUERY TIME ORDER ; the counter is : 94 The time server receive order : QUERY TIME ORDER ; the counter is : 95 The time server receive order : QUERY TIME ORDER ; the counter is : 96 The time server receive order : QUERY TIME ORDER ; the counter is : 97 The time server receive order : QUERY TIME ORDER ; the counter is : 98 The time server receive order : QUERY TIME ORDER ; the counter is : 99 The time server receive order : QUERY TIME ORDER ; the counter is : 100 View Code客戶(hù)端運(yùn)行結(jié)果如下:
"D:\Program Files (x86)\Java\jdk1.8.0_65\bin\java" "-javaagent:D:\Program Files (x86)\JetBrains\IntelliJ IDEA 2017.1.4\lib\idea_rt.jar=62637:D:\Program Files (x86)\JetBrains\IntelliJ IDEA 2017.1.4\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\charsets.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\deploy.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\access-bridge-64.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\cldrdata.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\dnsns.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\jaccess.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\jfxrt.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\localedata.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\nashorn.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\sunec.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\sunjce_provider.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\sunmscapi.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\sunpkcs11.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\ext\zipfs.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\javaws.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\jce.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\jfr.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\jfxswt.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\jsse.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\management-agent.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\plugin.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\resources.jar;D:\Program Files (x86)\Java\jdk1.8.0_65\jre\lib\rt.jar;F:\01_Code\02_Idea\CoreInNetty\target\classes;C:\Users\lsf\.m2\repository\io\netty\netty-all\4.0.32.Final\netty-all-4.0.32.Final.jar;C:\Users\lsf\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.6.3\jackson-core-2.6.3.jar;C:\Users\lsf\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.6.3\jackson-databind-2.6.3.jar;C:\Users\lsf\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.6.0\jackson-annotations-2.6.0.jar" com.hust.grid.leesf.chapter4.correct.TimeClient Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 1 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 2 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 3 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 4 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 5 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 6 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 7 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 8 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 9 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 10 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 11 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 12 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 13 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 14 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 15 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 16 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 17 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 18 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 19 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 20 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 21 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 22 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 23 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 24 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 25 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 26 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 27 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 28 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 29 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 30 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 31 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 32 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 33 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 34 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 35 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 36 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 37 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 38 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 39 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 40 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 41 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 42 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 43 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 44 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 45 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 46 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 47 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 48 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 49 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 50 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 51 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 52 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 53 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 54 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 55 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 56 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 57 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 58 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 59 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 60 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 61 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 62 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 63 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 64 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 65 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 66 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 67 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 68 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 69 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 70 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 71 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 72 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 73 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 74 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 75 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 76 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 77 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 78 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 79 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 80 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 81 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 82 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 83 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 84 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 85 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 86 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 87 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 88 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 89 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 90 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 91 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 92 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 93 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 94 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 95 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 96 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 97 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 98 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 99 Now is : Wed Jun 28 16:12:25 CST 2017 ; the counter is : 100 View Code可以看到此時(shí)客戶(hù)端和服務(wù)端的消息發(fā)送和接收都已經(jīng)正常,不存在粘包問(wèn)題。
2.3 LineBasedFrameDecoder和StringDecoder解碼器說(shuō)明
LineBasedFrameDecoder會(huì)依次遍歷ByteBuf中的可讀字節(jié),判斷是否有\(zhòng)n或者\(yùn)r\n,其作為一行結(jié)束的標(biāo)志,其是支持以換行符為結(jié)束標(biāo)志的解碼器,支持?jǐn)y帶結(jié)束符和非結(jié)束符的兩種解碼方式,同時(shí)支持配置最大單行長(zhǎng)度,此時(shí),如果連續(xù)讀取最大長(zhǎng)度后仍未發(fā)現(xiàn)換行符,則會(huì)拋出異常,并忽略之前讀取的數(shù)據(jù)。
StringDecoder將接收的對(duì)象轉(zhuǎn)化為字符串,然后繼續(xù)調(diào)用后面的handler,LineBasedFrameDecoder和StringDecoder組合起來(lái)使用用來(lái)解決按行切換的文本解碼器。并且Netty中提供了豐富的解碼器和編碼器供使用,具體的可以參見(jiàn)官方文檔。
三、總結(jié)
本篇博文講解了TCP粘包,以及如何通過(guò)解碼器解決TCP粘包問(wèn)題,當(dāng)然,Netty除了提供按行切換的文本解碼器之外,還針對(duì)不同的應(yīng)用場(chǎng)景,提供了其他豐富的解碼器。謝謝各位園友的觀看~
轉(zhuǎn)載于:https://www.cnblogs.com/leesf456/p/7069679.html
總結(jié)
以上是生活随笔為你收集整理的【Netty】TCP粘包和拆包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 第一章 数据库概论
- 下一篇: Java往事之《返回整数的长度》