Netty writeAndFlush () incomplete

My tcp client netty server and netty server use writeAndFlush () return 393718 bytes. But the client only gets 262142 bytes. I am using "tcpdump -A" for apturing packages less than 393718. So I believe the isty not write function in writeAndFlush () function?

Here is the code

Tcp server:

public static void main (String args[]) {

        int processorsNumber = Runtime.getRuntime().availableProcessors() * 3;
        ThreadFactory threadFactory = new DefaultThreadFactory("work thread pool");
        EventLoopGroup bossLoopGroup = new NioEventLoopGroup(1);
        EventLoopGroup workLoopGroup = new NioEventLoopGroup(processorsNumber, threadFactory, SelectorProvider.provider());

        try {
            ServerBootstrap sb = new ServerBootstrap();
            sb.group(bossLoopGroup , workLoopGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            //ch.pipeline().addLast(new LineBasedFrameDecoder(1000));
                            ch.pipeline().addLast(new TcpServerHandler());
                        }
                    });

            sb.bind(new InetSocketAddress("0.0.0.0", 18881)).sync().channel().closeFuture().sync();
        } catch (InterruptedException e) {
            logger.error("netty error", e);
            e.printStackTrace();
        } finally {
            bossLoopGroup.shutdownGracefully();
            workLoopGroup.shutdownGracefully();
        }
    }

      

server handler:

public void channelRead(ChannelHandlerContext ctx, Object msg) {

        ByteBuf in = (ByteBuf) msg;
        String cmd = in.toString(CharsetUtil.UTF_8);
        logger.info(cmd);

        String retCode = "";
        String file = "E:\\sz\\app.log";
        try {
            FileReader fr = new FileReader(file);
            BufferedReader br = new BufferedReader(fr);
            String buffer = null;
            while ((buffer = br.readLine()) != null) {
                retCode += buffer;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        logger.info("return:" + retCode);
        byte[] result = retCode.getBytes();
        logger.info("======================="+result.length);
        ByteBuf resultBuf = Unpooled.buffer(result.length);
        resultBuf.writeBytes(result);
        ctx.writeAndFlush(resultBuf);

        ctx.close();
    }

      

tcp client:

public static void main(String[] args) {
        StringBuilder response = new StringBuilder();
        try {
            Socket socket = new Socket();
            InetSocketAddress address = new InetSocketAddress("127.0.0.1", 18881);
            socket.connect(address, 3000);
            socket.setSoTimeout(10 * 1000);

            OutputStream clientRequest = socket.getOutputStream();
            String cmd = "cmd";
            clientRequest.write(cmd.getBytes());
            clientRequest.flush();

            InputStream clientResponse = socket.getInputStream();
            int maxLen = 1024;
            byte[] contextBytes = new byte[maxLen];
            int readLen;
            while ((readLen = clientResponse.read(contextBytes, 0, maxLen)) != -1) {
                response.append(new String(contextBytes, 0, readLen));
            }

            clientRequest.close();
            clientResponse.close();
        } catch (IOException e) {
            logger.error("tcp error", e);
            e.printStackTrace();
        }
        String result = response.toString();
        System.out.println(result);
        System.out.println(result.getBytes().length);
    }

      

+3


source to share


1 answer


You close the connection immediately after recording, async, this requires problems.

What's happening here is that a new incoming message comes in your channelRead

Netty stream. This message is then advanced through your handler and finally sent using writeAndFlush

, however this call to send data back happens partially in the background and so the code keeps moving forward after which it sees the call to close the connection, it happily does so at this point since you said it.

What is happening at the moment is a race condition between the TCP layer trying to send data and the TCP layer that gets the call to close the connection, due to buffers used in different parts of the layers, so that the limit is 262142 bytes, however this the limit can fluctuate if unknown aspects change the connection.



The solution to this problem is waiting until Netty says that the record was successful, and only then close it. Since we don't want to wait in an asynchronous application, this means that we have to register a listener, luck is on our side in this case, and netty provides us with a listener that just closes the channel for us. You can use it like this:

ctx.writeAndFlush(resultBuf).addListener(ChannelFutureListener.CLOSE);

      

+3


source







All Articles