左
左羊
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