Mina, Netty, and Twisted (3): Fixed TCP Message prefix (Header), nettytwisted

Source: Internet
Author: User

Mina, Netty, and Twisted (3): Fixed TCP Message prefix (Header), nettytwisted

In the previous blog, we introduced how to use linefeeds to separate messages. However, this method has a small problem. If the message itself contains a line break, the message will be divided into two parts, and the result is incorrect.

This article introduces another message segmentation method, that is, the first article in the previous blog: use a fixed length header that indicates the length of the body, use a Header prefix with a fixed number of characters to specify the number of bytes of the Body to separate messages.

In the preceding figure, the Header is fixed to 4 bytes, And the Header stores a 4-byte (32-bit) integer. For example, 12 is 0x0000000C, this integer is used to specify the length (number of bytes) of the Body ). After reading so many bytes of Body, it is the Header of the Next message.

MINA, Netty, and Twisted are used for message splitting and decoding respectively.

MINA:

MINA provides PrefixedStringCodecFactory to encode and decode messages of this type. The default Header size of PrefixedStringCodecFactory is 4 bytes, and can also be specified as 1 or 2.

Public class TcpServer {public static void main (String [] args) throws IOException {IoAcceptor acceptor = new NioSocketAcceptor (); // The number of bytes of the Body specified by the 4-byte Header, acceptor for processing such messages. getFilterChain (). addLast ("codec", new ProtocolCodecFilter (new PrefixedStringCodecFactory (Charset. forName ("UTF-8"); acceptor. setHandler (new TcpServerHandle (); acceptor. bind (new InetSocketAddress (8080);} class TcpServerHandle extends IoHandlerAdapter {@ Override public void exceptionCaught (IoSession session, Throwable cause) throws Exception {cause. printStackTrace ();} // receives new data @ Override public void messageReceived (IoSession session, Object message) throws Exception {String msg = (String) message; System. out. println ("messageReceived:" + msg) ;}@ Override public void sessionCreated (IoSession session) throws Exception {System. out. println ("sessionCreated") ;}@ Override public void sessionClosed (IoSession session) throws Exception {System. out. println ("sessionClosed ");}}

Netty:

Netty uses LengthFieldBasedFrameDecoder to process such messages. The new round (80, 0, 4, 0, 4) in the following code contains five parameters: int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip. MaxFrameLength is the maximum length of the message, the position of lengthFieldOffset is the Header, the length of lengthFieldLength is the Header, and the length of lengthAdjustment is adjusted (the default value in the Header indicates the length of the Body and does not ), initialBytesToStrip is used to remove the number of bytes (all content of Header + Body is returned after decoding by default. If this parameter is set to 4, the Header of 4 bytes is removed and only the Body is left ).

Public class TcpServer {public static void main (String [] args) throws InterruptedException {EventLoopGroup bossGroup = new NioEventLoopGroup (); EventLoopGroup workerGroup = new NioEventLoopGroup (); try {ServerBootstrap B = new ServerBootstrap (); B. group (bossGroup, workerGroup ). channel (NioServerSocketChannel. class ). childHandler (new ChannelInitializer <SocketChannel> () {@ Override public void initChannel (SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch. pipeline (); // LengthFieldBasedFrameDecoder splits messages by line and retrieves the body pipeline. addLast (new LengthFieldBasedFrameDecoder (80, 0, 4, 0, 4); // convert it to a string pipeline encoded by UTF-8. addLast (new StringDecoder (CharsetUtil. UTF_8); pipeline. addLast (new TcpServerHandler () ;}}); ChannelFuture f = B. bind (8080 ). sync (); f. channel (). closeFuture (). sync ();} finally {workerGroup. shutdownGracefully (); bossGroup. shutdownGracefully () ;}} class TcpServerHandler extends ChannelInboundHandlerAdapter {// receives new data @ Override public void channelRead (ChannelHandlerContext ctx, Object msg) {String message = (String) msg; system. out. println ("channelRead:" + message) ;}@ Override public void channelActive (ChannelHandlerContext ctx) {System. out. println ("channelActive") ;}@ Override public void channelInactive (ChannelHandlerContext ctx) {System. out. println ("channelInactive") ;}@ Override public void exceptionCaught (ChannelHandlerContext ctx, Throwable cause) {cause. printStackTrace (); ctx. close ();}}

Twisted:

In Twisted, Int32StringReceiver must be inherited instead of Protocol. Int32StringReceiver indicates a fixed 32-bit (4-byte) Header, as well as Int16StringReceiver and Int8StringReceiver. The method to accept data events is not dataReceived or lineReceived, but stringReceived.

#-*-Coding: UTF-8-*-from twisted. protocols. basic import Int32StringReceiver from twisted. internet. protocol import Factory from twisted. internet import reactor class TcpServerHandle (Int32StringReceiver): # create a new connection def connectionMade (self): print 'ononmade '# Disconnect def connectionLost (self, reason ): print 'connectionlost' # receives new data def stringReceived (self, data): print 'stringreceived: '+ data factory = Factory () factory. protocol = TcpServerHandle reactor. listenTCP (8080, factory) reactor. run ()

The following is a client test program written in Java:

Public class TcpClient {public static void main (String [] args) throws IOException {Socket socket = null; DataOutputStream out = null; try {socket = new Socket ("localhost ", 8080); out = new DataOutputStream (socket. getOutputStream (); // request Server String data1 = "Newton"; byte [] outputBytes1 = data1.getBytes ("UTF-8"); out. writeInt (outputBytes1.length); // write header out. write (outputBytes1); // write body String data2 = "Einstein"; byte [] outputBytes2 = data2.getBytes ("UTF-8"); out. writeInt (outputBytes2.length); // write header out. write (outputBytes2); // write body out. flush ();} finally {// close the connection out. close (); socket. close ();}}}

MINA server output result:

SessionCreated
MessageReceived: Newton
MessageReceived: Einstein
SessionClosed

Netty server output result:

ChannelActive
ChannelRead: Newton
ChannelRead: Einstein
ChannelInactive

Twisted server output result:

ConnectionMade
StringReceived: Newton
StringReceived: Einstein
ConnectionLost




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.