Simple Use of Netty Framework to Realize socket Communication

As an aside, many people call the NIO provided by JDK 1.4 asynchronous non-blocking I/O; in fact, it is not. Strictly speaking, it can only be called non-blocking I/O. In NIO 2.0 provided by JDK 1.7, an asynchronous socket channel Channel is added, which is the real asynchronous non-blocking I/O. The following table compares different I/O models:

Table 1-1 Several I/O Models and Homoenergetic Comparison

Synchronized Blocking I/O(BIO) Pseudo asynchronous I/O Non-blocking I/O(NIO) Asynchronous I/O(AIO)
Number of clients: I/O threads 1:1 M:N(M can be greater than N) M: 1 (one I/O thread handles multiple client connections)
I/O type (blocking) Blocking I/O Blocking I/O Non blocking I/O
I/O type (synchronization) Synchronous I/O Synchronous I/O Synchronized I/O(I/O multiplexing)
The difficulty of using API simple simple Very complicated
Debugging difficulty simple simple complex
reliability Very poor difference high
throughput low in high

brief introduction

_Netty is created by JBOSS One provided java open source Frame. Netty provides asynchronous, event driven Network application framework and tools for rapid development of high performance, high reliability Network Server And client programs.

In other words, Netty is a NIO-based client-server programming framework. Using Netty, you can ensure that you develop a network application quickly and simply, such as a client who implements a certain protocol. Server side Application. Netty considerably simplifies and streamlines the programming and development process of network applications, such as socket service development for TCP and UDP.

"Fast" and "simple" don't cause maintenance or performance problems. Netty is an implementation experience of a variety of protocols, including FTP,SMTP,HTTP, various binary, text protocols, and after a fairly well-designed project, Netty successfully found a way to ensure that it is easy to develop while also ensuring the performance, stability and scalability of its applications. —— Baidu Encyclopedia

Advantage

  1. API is simple to use and low threshold for development

  2. Powerful, preset a variety of coding and decoding functions, support a variety of mainstream protocols

  3. High performance, netty has the highest overall performance compared with other mainstream NIO frameworks in the industry

  4. Mature, stable, Netty has fixed all JDK NIO BUG s that have been found, and business developers no longer need to worry about NIO bug s.

  5. The community is active, the iteration cycle of versions is short, bug s can be found and fixed in time, and more new functions can be added at the same time.

  6. After experiencing a large-scale business test, it can only be verified.

Packing and unpacking

concept

TCP is a stream protocol. The so-called stream is a string of data without boundaries. Consider the flow of water in the river. They have no boundaries. The bottom layer of TCP does not understand the specific meaning of business layer data. It divides packets according to the actual situation of TCP buffer. So in business, it is believed that a complete package may be split into several packets to send, or it may encapsulate several small packets into one big data to send together. This is the so-called TCP sticking and unpacking problem.

Causes

  1. The byte size written by the application write is larger than the size of the socket interface sending buffer.

  2. tcp Segmentation of MSS Size

  3. payload of Ethernet frames is larger than MTU for IP fragmentation

Solution

  1. Message length, fixed length per message size, insufficient complement 0

  2. Increase the return line break at the end of the package for segmentation. For example: FTP protocol

  3. The message is divided into header and body. The total length field containing the message in the header

  4. More Complex Application Layer Protocol

Solutions to Netty Framework

_LineBasedFrameDecoder and StringDecoder classes

LineBasedFrameDecoder

The working principle of_Line Based Frame Decoder is to traverse the readable bytes in ByteBuf in turn to determine whether there are " r" or " r n", and if there is an end position, the bytes from the readable index position to the end interval form a line. It is a decoder that uses line break as the end sign. It supports two decoding methods, one is carrying the end sign and the other is without the end sign. It also supports the maximum length of configuring a single line. If the newline character is not found after reading the maximum length continuously, an exception will be thrown, and the abnormal flow read before will be ignored.

StringDecoder

The function of String Decoder is very simple, that is, to change the received object into a string, and then continue to call the handler. The combination of Line Based Frame Decoder and String Decoder is to switch the text decoder according to the newline character. It is designed to support TCP packet sticking and unpacking. Netty supports other symbol decoders (Delimiter BasedFrameDecode)

_Having said so much, here comes the code, which is the heartbeat realized by Netty. For the advanced stage of lazy cancer, it has been wind-packed, can be used directly in the past, and the notes are clearly written.

import android.util.Log;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
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;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

/**
 * @author Hai Chen Yi
 * @date 2018/2/6
 * @desc
 */
public class SocketTcp {
  private static SocketTcp socketTcp = new SocketTcp();
  private Channel channel = null;
  private EventLoopGroup group;
  private int port;
  private String host;

  public static SocketTcp getInstance() {
    return socketTcp;
  }

  public SocketTcp setPort(int port) {
    this.port = port;
    return this;
  }

  public SocketTcp setHost(String host) {
    this.host = host;
    return this;
  }

  public void connect() {
    if (channel != null) return;
    if (group == null) {
      //NIO thread group
      group = new NioEventLoopGroup();
    }
    try {//Configure Bootstrap
      Bootstrap bootstrap = new Bootstrap();
      bootstrap.group(group)
          .channel(NioSocketChannel.class)
          .option(ChannelOption.TCP_NODELAY, true)
          .handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
              //End with line breaks
              ChannelPipeline pipeline = ch.pipeline();
              pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
              pipeline.addLast(new LineBasedFrameDecoder(Integer.MAX_VALUE));
              pipeline.addLast(new StringDecoder());
              pipeline.addLast(new MyHeartSocket());

              //Use "$" as the delimiter
              /*ChannelPipeline pipeline = ch.pipeline();
              pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
              String s = "$_";
              ByteBuf byteBuf = Unpooled.copiedBuffer(s.getBytes());
              pipeline.addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE,byteBuf));
              pipeline.addLast(new StringDecoder());
              pipeline.addLast(new MyHeartSocket());*/

            }
          });
      //Initiate an asynchronous connection operation
      ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
      channel = channelFuture.channel();
      //Waiting for server listening port to close
      channel.closeFuture().sync();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      disConnect();
    }
  }

  /**
   * Disconnect the tcp connection.
   */
  private void disConnect() {
    if (null != group) {
      group.shutdownGracefully();
    }
    group = null;
    channel = null;
  }

  public void sendMessage(String msg) {//After successful connection, IO operation is performed through the interface provided by Channel
    try {
      if (channel != null && channel.isOpen()) {
        channel.writeAndFlush(msg).sync();
        Log.d("wz", "send succeed " + msg);
      } else {
        reConnect();
        throw new Exception("channel is null | closed");
      }
    } catch (Exception e) {
      reConnect();
      e.printStackTrace();
    }
  }

  /**
   * Reconnect.
   */
  private void reConnect() {
    new Thread(this::connect);
  }
}
package com.example.zwang.myapplication.socket;

import android.os.SystemClock;
import android.util.Log;

import java.util.concurrent.TimeUnit;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.EventLoop;
import io.netty.channel.SimpleChannelInboundHandler;


public class MyHeartSocket extends SimpleChannelInboundHandler<Object> {
  private ChannelHandlerContext ctx;
  private boolean isConnect = false;

  @Override
  protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
    Log.v("WZ", "Normal connection messageReceived");
    ByteBuf msg1 = (ByteBuf) msg;
    byte[] bytes = new byte[msg1.readableBytes()];
    msg1.readBytes(bytes);
    String s = new String(bytes, "UTF-8");
    Log.v("WZ", "Received messages:" + s);
  }

  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {
    super.channelActive(ctx);
    Log.v("WZ", "Normal connection channelActive");
    isConnect = true;
    if (this.ctx == null) {
      synchronized (MyHeartSocket.class) {
        if (this.ctx == null) {
          this.ctx = ctx;
          MyAppHeart();
        }
      }
    }
  }

  private void MyAppHeart() {
    new Thread(() -> {
      while (ctx != null && isConnect) {
        String data = "123";
        byte[] bytes = data.getBytes();
        if (isConnect) {
          ctx.writeAndFlush(Unpooled.buffer(bytes.length).writeBytes(bytes));
          SystemClock.sleep(3000);
        }
      }
    }).start();
  }

  @Override
  public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    EventLoop loop = ctx.channel().eventLoop();
    loop.schedule(() -> SocketTcp.getInstance().connect(), 5, TimeUnit.SECONDS);
    super.channelInactive(ctx);
    Log.v("WZ", "Reconnect socket The server");
    isConnect = false;
  }

  @Override
  public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    super.userEventTriggered(ctx, evt);
    Log.v("WZ", "Sending Packets");
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    super.exceptionCaught(ctx, cause);
    Log.v("WZ", "Connection abnormal");
    this.ctx.close();
    this.ctx = null;
  }
}

End

Keywords: Netty socket network JDK

Added by HyperD on Wed, 15 May 2019 16:44:34 +0300