[TOC]
Use and analysis of Linebasedframedecoder decoder in Netty: Solving the problem of TCP sticky packet
The previous article "Netty in TCP sticky packet problem code example and analysis" demonstrates the use of a time server example demonstrates the problem of TCP sticky packet, which is used LineBasedFrameDecoder
to solve the problem.
However, it is important to note that the LineBasedFrameDecoder
name is known for its meaning, it is related to the line, and in the previous presentation of the TCP sticky packet problem, the author is intentionally in the message sent to add a line break, the purpose is to explain in the later LineBasedFrameDecoder
use, of course, also gives a simple solution to the problem of the TCP sticky packet, Or a simple case to give us learners a more intuitive understanding.
The code came from chapter 4th of the Netty authoritative guide, but I still made some changes.
Service-Side Code Timeserver.java
Package Cn.xpleaf.netty02;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 void bind (int port) throws Exception { Configure the NIO thread group on the service side eventloopgroup Bossgroup = new Nioeventloopgroup (); Eventloopgroup Workergroup = new Nioeventloopgroup (); try {serverbootstrap b = new Serverbootstrap (); B.group (Bossgroup, Workergroup). Channel (nioserversocketchannel.class). Option (channeloption . So_backlog, 1024x768). Childhandler (New Childchannelhandler ()); Bind port, synchronization waits for success Channelfuture f = b.bind (port). sync (); Wait for the service-side listener port to close F.channel (). Closefuture (). sync (); } finally {//gracefully exits, releasing thread pool resource bossgroup.shutdowngracefully (); Workergroup.shutdowngracefully (); }} Private class Childchannelhandler extends Channelinitializer<socketchannel> {@Override prot ected void Initchannel (Socketchannel ch) throws Exception {//core in two lines below, added Linebasedframedecoder and Stringdecoder two Decoder//So when the message arrives at our business processing handler that is Timerserverhandler, the message that is seen//is the result of the previous two decoders being processed ch.pipeline ( ). AddLast (New Linebasedframedecoder (1024)); Ch.pipeline (). AddLast (New Stringdecoder ()); Ch.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 (port); } catch (NumberFormatException e) {//Todo:handle exception}} new Timeserver (). bind (port); }}
Timeserverhandler.java
Package Cn.xpleaf.netty02;import Java.sql.date;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;public class Timeserverhandler extends Channelinboundhandleradapter { private int counter = 0; @Override public void Channelread (Channelhandlercontext ctx, Object msg) throws Exception {String BODY = (Strin g) msg; The role of counter is to mark the number of times a client has received a request 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); } @Override public void Channelreadcomplete (Channelhandlercontext ctx) throws Exception {Ctx.flush (); } @Override public void Exceptioncaught (Channelhandlercontext ctx, throwable cause) {ctx.close (); }}
Client code Timeclient.java
Package Cn.xpleaf.netty02;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 void connect (int port, string host) throws Exception {//Configure client NIO thread Group Eventloopgroup group = new Nioeventloopgroup (); try {Bootstrap b = new Bootstrap (); B.group (Group). Channel (niosocketchannel.class). Option (Channeloption.tcp_nodelay, true). Han Dler (New channelinitializer<socketchannel> () {@Override protected void Initch Annel (Socketchannel ch) throws Exception { Core in the following two lines, added Linebasedframedecoder and stringdecoder two decoder//So when the message arrives our business processing handler namely Timerserv Erhandler, the messages you see//are the result of the previous two decoders being processed ch.pipeline (). AddLast (New LINEBASEDFR Amedecoder (1024)); Ch.pipeline (). AddLast (New Stringdecoder ()); Ch.pipeline (). AddLast (New Timeclienthandler ()); } }); Initiates an asynchronous connection operation channelfuture F = b.connect (host, port). sync (); Wait for the client link to close F.channel (). Closefuture (). sync (); } finally {//gracefully exits, releasing the NIO thread Group group.shutdowngracefully (); }} public static void Main (string[] args) throws Exception {int port = 8080; if (args! = null && args.length > 0) {try {port = integer.valueof (port); } catch (NumberFormatException e) {//with default}} new TImeclient (). Connect (port, "localhost"); }}
Timeclienthandler.java
Package Cn.xpleaf.netty02;import Java.util.logging.logger;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;public Class Timeclienthandler extends Channelinboundhandleradapter {private static final Logger Logger = Logger.getlogger (TimeServ ErHandler.class.getName ()); private int counter; Private byte[] req; Public Timeclienthandler () {req = ("QUERY time ORDER" + system.getproperty ("Line.separator")). GetBytes (); } @Override public void channelactive (Channelhandlercontext ctx) {BYTEBUF message = NULL; for (int i = 0; i < i++) {message = Unpooled.buffer (req.length); Message.writebytes (req); Ctx.writeandflush (message); }} @Override public void Channelread (Channelhandlercontext ctx, Object msg) throws Exception {String bod y = (String) msg; Counter's role is to mark this as the number of times a client request is received SYSTEM.OUT.PRINTLN ("Now is:" + body + "; The counter is: "+ ++counter); } @Override public void Exceptioncaught (Channelhandlercontext ctx, Throwable cause) throws Exception {Logger . Warning ("Unexpected exception from downstream:"); Ctx.close (); }}
Test
Server Run Results:
The time server receive order : QUERY TIME ORDER ; the counter is : 1The time server receive order : QUERY TIME ORDER ; the counter is : 2The time server receive order : QUERY TIME ORDER ; the counter is : 3...省略多行...The time server receive order : QUERY TIME ORDER ; the counter is : 98The time server receive order : QUERY TIME ORDER ; the counter is : 99The time server receive order : QUERY TIME ORDER ; the counter is : 100
Client Run Results:
Now is : 2018-02-11 ; the counter is : 1Now is : 2018-02-11 ; the counter is : 2Now is : 2018-02-11 ; the counter is : 3...省略多行...Now is : 2018-02-11 ; the counter is : 98Now is : 2018-02-11 ; the counter is : 99Now is : 2018-02-11 ; the counter is : 100
As can be seen from the output, this does solve the problem of TCP sticky packets.
Principle Analysis
The following analysis comes from the book, which is also posted here:
Use and analysis of Linebasedframedecoder decoder in Netty: Solving the problem of TCP sticky packet