Netty writeAndFlush()不完整

tai*_*yao 4 java tcp netty

我的tcp客户端请求Netty服务器,并且Netty服务器使用writeAndFlush()返回393718字节。但是客户端仅接收262142字节。我使用“ tcpdump -A”来设置数据包,也少于393718。所以我认为适当的是在netty writeAndFlush()函数中?

这是代码

tcp服务器:

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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

服务器处理程序:

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();
    }
Run Code Online (Sandbox Code Playgroud)

TCP客户端:

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);
    }
Run Code Online (Sandbox Code Playgroud)

Fer*_*big 6

您在异步框架中编写后直接关闭连接,这很麻烦。

这里发生的是,有一个新的传入消息是channelRead通过Netty线程到达您的。然后,此消息将通过您的处理程序进行处理,最后使用来将其发送回去writeAndFlush。但是,将数据发送回去的调用部分发生在后台,因此代码继续向前,然后看到了关闭连接的调用,因为您已经说过了,所以它很高兴在这一点上做到了。

此时发生的情况是,TCP层尝试发送数据,而TCP层接收到关闭连接的调用之间的竞争状态,由于在层的不同部分使用了缓冲区,因此发生了限制在262142字节处,但是如果连接的未知方面发生更改,此限制可能会波动。

解决此问题的方法是等待Netty说写入成功,然后关闭它。由于我们不想在异步应用程序中等待,因此这意味着我们必须注册一个侦听器,这种情况在我们这边很幸运,netty为我们提供了一个侦听器,该侦听器只是为我们关闭了通道。您可以像这样使用它:

ctx.writeAndFlush(resultBuf).addListener(ChannelFutureListener.CLOSE);
Run Code Online (Sandbox Code Playgroud)