左羊

V1

2022/12/13阅读:64主题:默认主题

【Netty】网络连接数上限造成的问题

Netty Socket压测报:Address already in use: no further information

最近左羊在做Netty Socket压力测试时,客户端连接数每次加压到4千左右时便会报出上述错误,特以此文记录下原因及解决方案。

环境介绍

Windows 10
JDK 1.8 
Netty 4.1.18.Final

代码示例

服务端

package cn.zy.testoneconnectionsnumber.netty_socket_server;
import cn.zy.testoneconnectionsnumber.ConvertCode;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.DefaultThreadFactory;
public class NettyServer {
    public static void main(String[] args) {
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("Server1"true));
        NioEventLoopGroup wokerGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("Server1"true));
        try{
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,wokerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
                            pipeline.addLast(new LengthFieldPrepender(4));
                            pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
                            pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
                            pipeline.addLast(new SimpleChannelInboundHandler<String>() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
                                    System.out.println(msg);
                                    channelHandlerContext.channel().writeAndFlush("Hello Netty Clinet!");
                                }
                            });
                        }
                    });
            //绑定端口号
            ChannelFuture channelFuture = bootstrap.bind(9999).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            wokerGroup.shutdownGracefully();
        }
    }
}

客户端

package cn.zy.testoneconnectionsnumber.netty_socket_client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.DefaultThreadFactory;
import java.time.LocalDateTime;
public class NettyClient {
    public static void main(String[] args) {
        NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("client1"true));
        for (int i = 0; i < 6000; i++) {
            int finalI = i;
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            pipeline.addLast(new LengthFieldPrepender(4));
                            pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
                            pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
                            pipeline.addLast(new SimpleChannelInboundHandler<String>() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
                                    System.out.println(msg);
                                    channelHandlerContext.writeAndFlush(LocalDateTime.now());
                                    channelHandlerContext.close();
                                }
                                @Override
                                public void channelActive(ChannelHandlerContext channelHandlerContext) throws Exception {
                                    channelHandlerContext.writeAndFlush(finalI + "Hello Netty Server!");
                                }
                            });
                        }
                    });
            try {
                ChannelFuture channelFuture = bootstrap.connect("localhost", 9999).sync();
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

造成原因

原因是Windows的默认最大TCP连接端口数(MaxUserPort)是5000,默认240秒释放之前的操作完的等待线程。由此造成本机开发环境压力测试,连接数达到3-4千时报错。

解决步骤

1、打开注册表:regedit(开始-运行-输入regedit,win+R - 输入regedit)。
2、\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters。
3、新建 DWORD值,name:TcpTimedWaitDe,value:30(十进制) –> 设置为30秒,默认是240秒。
4、新建 DWORD值,name:MaxUserPort,value:65534(十进制) –> 设置最大连接数65534,Windows的默认最大TCP连接端口数(MaxUserPort)是5000。
5、重启系统。

参考文献

码农教程 . http://www.manongjc.com/detail/27-wgzlsxgoyaywiiz.html . 超出TCP连接端口数限制(MaxUserPort)引起的服务器问题
博客园 . https://www.cnblogs.com/ngd-mzl/p/16409901.html . jmeter 性能测试 报错信息“address already in use:connect”解决方法
张彦飞 . 深入理解Linux网络 . 第八章 一台机器最多支持多少条TCP链接

分类:

后端

标签:

后端

作者介绍

左羊
V1