Netty learning two TCP stick package unpacking and unpacking solve Netty TCP stick package

1, TCP stick package unpacking

operating system

We all know that the core of the operating system kernel, independent of the application outside of the ordinary, you can access a protected memory space, but also all access to the underlying hardware.
To protect user processes can not directly access the kernel operations to ensure the safety of the kernel, the operating system is divided into two parts, one for the kernel space, another part of the user space.

I / O model

For security reasons the operating system, the process can not access I / O devices directly to complete the I / O operation must request the kernel through system calls, and the kernel for each I / O device maintains a buffer (buffer)

The whole process is requested:

1, a user initiates a request process, after the kernel receives a request to retrieve data from the buffer to the I / O device
2, and then the data copy buffer in the address space of the user process
again after the response to the client 3, the user process obtains the data end

Stick package and unpacking

Similarly, when the operating system sends data via the TCP protocol, also stored in the first data buffer, the buffer size is assumed that 1024 bytes

Stick package

If the packet transmission is relatively small, much smaller than the size of the buffer, TCP packets will be combined into a plurality of data packets, which occurred stick package

Unpacking

If the packet transmission is relatively large, much larger than the size of the buffer, TCP packet will be split into a plurality of data packets, which occurs unpacking

  • Server twice read two independent data packets, respectively D1 and D2, and not stick package unpacking
  • The server receives a packet two, D1 and D2 stick together, it occurred stick package
  • Server twice read two data packets, a complete read packet D1 and D2 D2_1 - part of the package, the second package to read the rest of the D2 D2_2
  • Server twice read two data packets, a read section points D1_1 D1, and the second to read the rest of the complete package D1_2 D1 and D2 of the packet

2, TCP stick package unpacking solve

For TCP stick package unpacking problem, the following four kinds of solutions

(1) fixed-length message, such as the size of each packet are 128 bytes, if not, fill a gap space

(2) the client using a fixed end delimiter of each packet, for example \ r \ n, if a packet is split up, which then waits for the \ r \ n after the next packet sent over, then subjected to after the split head portion merging with the remaining portion of the front of a bag, thus obtaining a complete package

(3) into a message header and a message body, the current stored in the entire length of the message header, the message only after the reading of sufficient length to be considered as a complete message read

(4) stick package and unpacking processing performed by custom protocol

3, Netty exemplary stick package unpacking

The client sends three messages to the server, the server after receiving the message or reply to a message client 3

Client

public class HelloWorldClient {

    private int port;
    private String address;

    public HelloWorldClient(int port, String address) {
        this.port = port;
        this.address = address;
    }

    public void start() {
        EventLoopGroup group = new NioEventLoopGroup();

        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group).channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>(){

                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        
                        pipeline.addLast("decoder", new StringDecoder());// 字符串解码和编码
                        pipeline.addLast("encoder", new StringEncoder());
                        pipeline.addLast("handler", new ChannelInboundHandlerAdapter(){
                            
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                System.out.println("客户端收到消息:[" + msg + "]");
                            }
                        });//自定义handler
                    }
                });

        try {
            ChannelFuture future = bootstrap.connect(address,port).sync();
            Channel channel = future.channel();
            channel.writeAndFlush("我是客户端,地址:" + channel.remoteAddress());
            channel.closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        HelloWorldClient client = new HelloWorldClient(8888, "127.0.0.1");
        client.start();
    }
}

Server

public class HelloWorldServer {

    private int port;
    
    public HelloWorldServer(int port) {
        this.port = port;
    }
    
    public void start(){
        EventLoopGroup bossGroup = new NioEventLoopGroup();//创建父子线程组
        EventLoopGroup workGroup = new NioEventLoopGroup();
        
        ServerBootstrap server = new ServerBootstrap();
        server.group(bossGroup, workGroup)
              .channel(NioServerSocketChannel.class)//指定处理客户端的通道
              .childHandler(new ChannelInitializer<SocketChannel>(){

                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    
                    pipeline.addLast("decoder", new StringDecoder());// 字符串解码和编码
                    pipeline.addLast("encoder", new StringEncoder());
                    pipeline.addLast("handler", new ChannelInboundHandlerAdapter(){
                        
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            System.out.println("服务端收到消息:[" + msg + "]");
                            ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));
                            ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));
                            ctx.writeAndFlush(Unpooled.copiedBuffer("我是服务端".getBytes()));
                        }
                    });//自定义handler
                }
              });//通道初始化
        try {
            ChannelFuture future = server.bind(port).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        HelloWorldServer server = new HelloWorldServer(8888);
        server.start();
    }
}

The result:
the server

Client

You can see, the client received three messages are stuck together

4, Netty solve the stick package unpacking

4.1, the use of fixed-length solve

The client add FixedLengthFrameDecoder news fixed-length decoder, the server without treatment

operation result

You can see, the message received by the client is indeed divided by the number of bytes, but due to the length of a message is more than 10 bytes, so in the face of Chinese characters, will occur garbled, which is the fixed-length delimiter shortcomings

4.2, using delimiter

Client modifies initChannel method, as defined $ delimiter

At the end of the message server custom separator plus $

So the message is that the client receives a separate message, no stick package

Guess you like

Origin www.cnblogs.com/lmj612/p/10976194.html