In the previous blog post, there are ways to split messages with newline characters. However, this method has a small problem, if the message itself contains a newline character, it will split the message into two, the result is wrong.
This article introduces another way of message segmentation, which is the 2nd article in the previous blog post: Use a fixed length header that indicates the length of the body, with a fixed number of bytes in the header prefix to specify the number of bytes in the body, To split the message.
The header in the figure above is fixed to 4 bytes, and the header holds a 4-byte (32-bit) integer, such as 12, which is 0x0000000c, which is used to specify the length of the body (in bytes). After reading so many bytes of body, it is the header of the next message.
The following respectively with Mina, Netty, twisted to achieve this kind of message and decoding.
MINA:
Mina provides prefixedstringcodecfactory to encode this type of message, prefixedstringcodecfactory the default header size is 4 bytes, and of course can be specified as 1 or 2.
Public classTCPServer { Public Static voidMain (string[] args)throwsIOException {ioacceptor acceptor=NewNiosocketacceptor (); //The 4-byte header specifies the number of bytes in the body, and the processing of such messagesAcceptor.getfilterchain (). AddLast ("codec", NewProtocolcodecfilter (NewPrefixedstringcodecfactory (Charset.forname ("UTF-8")))); Acceptor.sethandler (NewTcpserverhandle ()); Acceptor.bind (NewInetsocketaddress (8080)); } } classTcpserverhandleextendsIohandleradapter {@Override Public voidExceptioncaught (iosession session, Throwable Cause)throwsException {cause.printstacktrace (); } //Receive new Data@Override Public voidMessagereceived (iosession session, Object message)throwsException {String msg=(String) message; System.out.println ("Messagereceived:" +msg); } @Override Public voidSessioncreated (iosession session)throwsException {System.out.println ("Sessioncreated"); } @Override Public voidSessionclosed (iosession session)throwsException {System.out.println ("Sessionclosed"); } }
Netty:
Netty uses Lengthfieldbasedframedecoder to handle this kind of message. The new Lengthfieldbasedframedecoder (80, 0, 4, 0, 4) in the code below contains 5 parameters, namely int maxframelength, int lengthfieldoffset, int lengthfieldlength, int lengthadjustment, int initialbytestostrip. Maxframelength is the maximum length of the message, Lengthfieldoffset is the position of the header, Lengthfieldlength is the length of the header, Lengthadjustment is the length adjustment (the value in the default header indicates the length of the body and does not include the header itself), Initialbytestostrip to remove the bytes (the default decoding returns the entire contents of Header+body, This is set to 4 to remove the 4-byte header, leaving only the body).
Public classTCPServer { Public Static voidMain (string[] args)throwsinterruptedexception {eventloopgroup bossgroup=NewNioeventloopgroup (); Eventloopgroup Workergroup=NewNioeventloopgroup (); Try{Serverbootstrap b=NewServerbootstrap (); B.group (Bossgroup, Workergroup). Channel (Nioserversocketchannel.class). Childhandler (NewChannelinitializer<socketchannel>() {@Override Public voidinitchannel (socketchannel ch)throwsException {Channelpipeline pipeline=Ch.pipeline (); //Lengthfieldbasedframedecoder Split messages by row, remove bodyPipeline.addlast (NewLengthfieldbasedframedecoder (80, 0, 4, 0, 4)); //then press UTF-8 encoding to convert to stringPipeline.addlast (NewStringdecoder (charsetutil.utf_8)); Pipeline.addlast (NewTcpserverhandler ()); } }); Channelfuture F= B.bind (8080). sync (); F.channel (). Closefuture (). sync (); } finally{workergroup.shutdowngracefully (); Bossgroup.shutdowngracefully (); } } } classTcpserverhandlerextendsChannelinboundhandleradapter {//Receive new Data@Override Public voidChannelread (Channelhandlercontext ctx, Object msg) {String message=(String) msg; System.out.println ("Channelread:" +message); } @Override Public voidchannelactive (Channelhandlercontext ctx) {System.out.println ("Channelactive"); } @Override Public voidchannelinactive (Channelhandlercontext ctx) {System.out.println ("Channelinactive"); } @Override Public voidexceptioncaught (Channelhandlercontext ctx, throwable cause) {cause.printstacktrace (); Ctx.close (); } }
Twisted:
You need to inherit int32stringreceiver in twisted and no longer inherit protocol. The int32stringreceiver represents a fixed 32-bit (4-byte) header, plus int16stringreceiver, int8stringreceiver, and so on. The method of accepting data events that need to be implemented is no longer datareceived, nor linereceived, but stringreceived.
#-*-coding:utf-8–*- fromTwisted.protocols.basicImportInt32stringreceiver fromTwisted.internet.protocolImportFactory fromTwisted.internetImportreactorclassTcpserverhandle (int32stringreceiver):#The new connection is established defConnectionmade (self):Print 'Connectionmade' #Connection Disconnect defconnectionlost (self, Reason):Print 'Connectionlost' #Receive new Data defstringreceived (self, data):Print 'stringreceived:'+Data Factory=Factory () Factory.protocol=Tcpserverhandle reactor.listentcp (8080, Factory) Reactor.run ()
Here is a client-side test program written in Java:
Public classTcpClient { Public Static voidMain (string[] args)throwsIOException {Socket Socket=NULL; DataOutputStream out=NULL; Try{Socket=NewSocket ("localhost", 8080); out=NewDataOutputStream (Socket.getoutputstream ()); //Request ServerString data1 = "Newton"; byte[] outputBytes1 = Data1.getbytes ("UTF-8"); Out.writeint (outputbytes1.length); //Write HeaderOut.write (OUTPUTBYTES1);//Write BodyString data2= "Einstein"; byte[] OutputBytes2 = Data2.getbytes ("UTF-8"); Out.writeint (outputbytes2.length); //Write HeaderOut.write (OutputBytes2);//Write BodyOut.flush (); } finally { //Close ConnectionOut.close (); Socket.close (); } } }
Mina Server output results:
sessioncreated
Messagereceived: Newton
Messagereceived: Einstein
Sessionclosed
Netty Server Output results:
Channelactive
Channelread: Newton
Channelread: Einstein
Channelinactive
Twisted Server Output results:
Connectionmade
Stringreceived: Newton
Stringreceived: Einstein
Connectionlost
Mina, Netty, Twisted learn Together (iii): TCP message fixed-size prefix (Header)