UDP two-way communication based on Netty

1. Channel inheritance relationship

For the principle of ChannelPipeline, please refer to: https://blog.csdn.net/qq_21033663/article/details/105674261
insert image description here

2. Classification of NIO Channels

1) NioDatagramChannel : send and receive data packets, support TCP and UDP, encapsulate DatagramSocket and selector
2) NioServerSocketChannel : used by the server, encapsulate the ServerSocketChannel of JDK
3) NioSocketChannel : used by the client

3、UDP Demo

1)Server

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;

public class UdpServerTest {
    
    
    public static void main(String[] args) throws Exception {
    
    
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootStrap = new Bootstrap();
        bootStrap.group(group)
                .channel(NioDatagramChannel.class) // 指定传输数据包,可支持UDP
                .option(ChannelOption.SO_BROADCAST, true) // 广播模式
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) // 线程池复用缓冲区
                .handler(new UDPServerHandler());
        Channel channel = bootStrap.bind(8888).sync().channel();
        // 这里阻塞
        channel.closeFuture().await();
    }

    static class UDPServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
    
    

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
    
    
            // 读取数据
            ByteBuf byteBuf = packet.content();
            byte[] bytes = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(bytes);
            System.out.println("receive client msg:" + new String(bytes));
            String test = "我是server";
            byte[] resBytes = test.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(Unpooled.copiedBuffer(resBytes), packet.sender());
            ctx.writeAndFlush(sendPacket);
        }
    }
}

2)Client

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import java.net.InetSocketAddress;

public class UdpClientTest {
    
    
    public static void main(String[] args) throws Exception {
    
    
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .handler(new UdpClientHandler());
        Channel ch = b.bind(7777).sync().channel();
        String test = "我是client";
        byte[] bytes = test.getBytes();
        ByteBuf byteBuf = Unpooled.copiedBuffer(bytes);
        ch.writeAndFlush(new DatagramPacket(byteBuf,
                    new InetSocketAddress("127.0.0.1", 8888))).sync();
        // 客户端等待10s用于接收服务端的应答消息,然后退出并释放资源
        ch.closeFuture().await(10000);

    }

    private static class UdpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
    
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) {
    
    
            ByteBuf byteBuf = msg.content();
            byte[] bytes = new byte[byteBuf.readableBytes()];
            byteBuf.readBytes(bytes);
            System.out.println("receive server msg:" + new String(bytes));
        }
    }
}

4. ChannelOption configuration instructions

1) ALLOCATOR
  ByteBuf allocator (reuse buffer), the default value is ByteBufAllocator.DEFAULT, version 4.0 is UnpooledByteBufAllocator, version 4.1 is PooledByteBufAllocator. This value can also be configured using the system parameter io.netty.allocator.type
Note: Netty4.1 uses object pools and reuses buffers. You can directly configure
bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
bootstrap.childOption (ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
2) RCVBUF_ALLOCATOR
  is used for Channel to allocate receive buffer allocator. The default value is AdaptiveRecvByteBufAllocator.DEFAULT. It is an adaptive receive buffer allocator that can automatically adjust the size according to the received data. Optional value is FixedRecvByteBufAllocator, a fixed-size accept buffer allocator
3) MESSAGE_SIZE_ESTIMATOR
  message size estimator, the default is DefaultMessageSizeEstimator.DEFAULT. Estimate the size of ByteBuf, ByteBufHolder, and FileRegion, where ByteBuf and ByteBufHolder are the actual size, and the estimated value of FileRegion is 0. The number of bytes estimated by this value is used when calculating the water level. If the FileRegion is 0, it can be seen that the FileRegion does not affect the high and low water levels.
4) CONNECT_TIMEOUT_MILLIS
  connection timeout milliseconds, the default value is 30000 milliseconds or 30 seconds
5) MAX_MESSAGES_PER_READ
  The maximum number of messages read by a Loop, for ServerChannel or NioByteChannel, the default value is 16, and the default value for other Channels is 1. The default value is set in this way because: ServerChannel needs to accept enough connections to ensure high throughput, NioByteChannel can reduce unnecessary system calls select
6) WRITE_SPIN_COUNT
  The maximum number of times a Loop write operation is executed, and the default value is 16. That is to say, a maximum of 16 write operations are performed for a large amount of data. If the data is not completely written after 16 write operations, a new write task will be submitted to EventLoop at this time, and the task will continue to be executed in the next scheduling. In this way, other write requests can be responded and will not be delayed due to a single large data write request.
7) WRITE_BUFFER_HIGH_WATER_MARK
  write high water mark, the default value is 64KB. If the bytes in Netty's write buffer exceed this value, Channel's isWritable() returns False
8) WRITE_BUFFER_LOW_WATER_MARK
  writes the low water mark, the default value is 32KB. When the bytes in Netty's write buffer exceed the high water level and drop to the low water level, Channel's isWritable() returns True. Write high and low water marks allow the user to control the rate at which data is written, enabling flow control. The recommended method is: each time the channel.write(msg) method is called, first call channel.isWritable() to determine whether it is writable
9) WRITE_BUFFER_WATER_MARK
10) ALLOW_HALF_CLOSURE
  When closing the connection, half-close is allowed, and it is not allowed by default.
11) AUTO_READ
  automatically reads, and the default value is True. Netty only sets up to care about the corresponding I/O events when necessary. For read operations, you need to call channel.read() to set the I/O event you care about to OP_READ, so that if there is data arriving, it can be read for user processing. When the value is True, channel.read() will be called automatically after each read operation, so that the data can be read when it arrives; otherwise, the user needs to manually call channel.read(). It should be noted that when the config.setAutoRead(boolean) method is called, if the status changes from false to true, the channel.read() method will be called to read the data; from true to false, config.autoReadCleared() will be called Method to terminate data reading
12) AUTO_CLOSE
13) SO_BROADCAST
  broadcast
14) SO_KEEPALIVE
  connection keep alive, the default value is False. When this function is enabled, TCP will actively detect the validity of idle connections. This function can be regarded as the heartbeat mechanism of TCP. It should be noted that: the default heartbeat interval is 7200s, which is 2 hours. Netty disables this function by default.
15) SO_SNDBUF
  sets the size of the send buffer, which is used to save the send data until the send is successful.
  The size of the TCP data send buffer. The buffer is the TCP sending sliding window, and the Linux operating system can use the command: cat /proc/sys/net/ipv4/tcp_smem to query its size
16) SO_RCVBUF
  sets the size of the receiving buffer, which is used to save the network protocol station received to the data until the program reads successfully
  TCP data receive buffer size. The buffer is the TCP receiving sliding window, and the Linux operating system can use the command: cat /proc/sys/net/ipv4/tcp_rmem to query its size. Generally, this value can be set by the user at any time, but when the set value exceeds 64KB, it needs to be set before connecting to the remote end.
17) SO_REUSEADDR
  depends on the network environment and your own confidence. If the network environment is good, there will be no "lose" packets if there is information, and you think ACK can be sent to the server, then you can consider enabling SO_REUSEADDR (default off)
18) SO_LINGER
  The delay time for closing the Socket, the default value is -1, which means that this function is disabled. -1 means that the socket.close() method returns immediately, but the bottom layer of the OS will send all the send buffers to the peer. 0 means that the socket.close() method returns immediately, the OS discards the data in the sending buffer and directly sends an RST packet to the peer, and the peer receives a reset error. A non-zero integer value means that the thread calling the socket.close() method will be blocked until the delay time expires or the data in the sending buffer is sent. If the timeout expires, the peer will receive a reset error.
19) SO_BACKLOG
  BACKLOG is used to construct the ServerSocket object of the server socket, which identifies the maximum length of the queue used to temporarily store the requests that have completed the three-way handshake when the server request processing threads are all in work (run out). If it is not set or the set value is less than 1, Java will use the default value 50
20) SO_TIMEOUT
  is used to set the timeout time for waiting for receiving data, in milliseconds, and its default value is 0, which means infinite waiting.
21) IP_TOS
  IP parameter, set the Type-of-Service field of the IP header, which is used to describe the priority and QoS option of the IP packet
22) IP_MULTICAST_ADDR
  Corresponding to the IP parameter IP_MULTICAST_IF, set the network card corresponding to the address to multicast mode
23) IP_MULTICAST_IF
  corresponds to the IP parameter IP_MULTICAST_IF2, the same as above but supports IPV6
24) IP_MULTICAST_TTL
  IP parameter, the time-to-live of the multicast datagram is the number of surviving hops
25) IP_MULTICAST_LOOP_DISABLED
  corresponds to IP parameter IP_MULTICAST_LOOP, set the multicast function of the local loopback interface. Since IP_MULTICAST_LOOP returns True to indicate shutdown, Netty adds the suffix _DISABLED to prevent ambiguity.
26) TCP_NODELAY
  corresponds to TCP_NODELAY in the socket option. The use of this parameter is related to the Nagle algorithm. The Nagle algorithm assembles small data packets into larger frames and sends them instead of sending a data packet once. The purpose is to Improve the efficiency of each transmission, so when the data packet does not form a large enough frame, the transmission of the data packet will be delayed. Although the network load is increased, the delay is caused. If the TCP_NODELAY parameter is set to true, the Nagle algorithm can be disabled , that is, the real-time transmission of small packets
  TCP_NODELAY is used to enable or disable the Nagle algorithm. If high real-time performance is required, the data will be sent immediately when there is data to be sent. Set this option to true to turn off the Nagle algorithm; if you want to reduce the number of sending times and reduce network interaction, set it to false and wait for a certain size to be accumulated before sending. The default is false.
27)
  The EventLoop registered by DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION DatagramChannel is activated
28) SINGLE_EVENTEXECUTOR_PER_GROUP
  executes events in ChannelPipeline in a single thread, and the default value is True. This value controls the thread that executes the ChannelHandler in the ChannelPipeline. If it is True, the entire pipeline is executed by one thread, so there is no need for thread switching and thread synchronization, which is recommended by Netty4; if it is False, the processing in ChannelHandler will be executed by different threads in the Group

Guess you like

Origin blog.csdn.net/qq_21033663/article/details/113773141