最近写了个客户端压测工具结果每次压到将近5000时就会报错,也是搞了两天才发现问题,主要是错误表现和网上大多数人的表现一样,导致忽略了眼前的错误提示
错误表现具体如下:
java.lang.IllegalStateException: failed to create a child event loop
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:88)
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:58)
at io.netty.channel.MultithreadEventLoopGroup.<init>(MultithreadEventLoopGroup.java:52)
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:87)
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:82)
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:63)
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:51)
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:43)
at com.sy599.game.server.ClientServer.connect(ClientServer.java:30)
at com.sy599.game.client.base.Client0.connect(Client0.java:123)
at com.sy599.game.client.base.Client0.<init>(Client0.java:68)
at com.sy599.game.client.MatchClient.<init>(MatchClient.java:70)
at com.sy599.game.test.match.ClientBatchTest.lambda$batchLoginAndMatchTest$4(ClientBatchTest.java:160)
at com.sy599.game.test.match.ClientBatchTest.lambda$batchInvoke$1(ClientBatchTest.java:38)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: io.netty.channel.ChannelException: failed to open a new selector
at io.netty.channel.nio.NioEventLoop.openSelector(NioEventLoop.java:175)
at io.netty.channel.nio.NioEventLoop.<init>(NioEventLoop.java:149)
at io.netty.channel.nio.NioEventLoopGroup.newChild(NioEventLoopGroup.java:127)
at io.netty.channel.nio.NioEventLoopGroup.newChild(NioEventLoopGroup.java:36)
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:84)
... 16 more
Caused by: java.io.IOException: Unable to establish loopback connection
at sun.nio.ch.PipeImpl$Initializer.run(PipeImpl.java:94)
at sun.nio.ch.PipeImpl$Initializer.run(PipeImpl.java:61)
at java.security.AccessController.doPrivileged(Native Method)
at sun.nio.ch.PipeImpl.<init>(PipeImpl.java:171)
at sun.nio.ch.SelectorProviderImpl.openPipe(SelectorProviderImpl.java:50)
at java.nio.channels.Pipe.open(Pipe.java:155)
at sun.nio.ch.WindowsSelectorImpl.<init>(WindowsSelectorImpl.java:127)
at sun.nio.ch.WindowsSelectorProvider.openSelector(WindowsSelectorProvider.java:44)
at io.netty.channel.nio.NioEventLoop.openSelector(NioEventLoop.java:173)
... 20 more
Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:433)
at sun.nio.ch.Net.bind(Net.java:425)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:67)
at sun.nio.ch.PipeImpl$Initializer$LoopbackConnector.run(PipeImpl.java:121)
at sun.nio.ch.PipeImpl$Initializer.run(PipeImpl.java:76)
... 28 more
java.lang.IllegalStateException: failed to create a child event loop
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:88)
at io.netty.util.concurrent.MultithreadEventExecutorGroup.<init>(MultithreadEventExecutorGroup.java:58)
at io.netty.channel.MultithreadEventLoopGroup.<init>(MultithreadEventLoopGroup.java:52)
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:87)
at io.netty.channel.nio.NioEventLoopGroup.<init>(NioEventLoopGroup.java:82)
核心代码如下:(每个新建的连接都会走上此处)
ClientHandler clientHandler = new ClientHandler(client);
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
final Bootstrap bootstrap = new Bootstrap();
clientHandler.getClient().setEventLoopGroup(eventLoopGroup);
clientHandler.getClient().setBootstrap(bootstrap);
bootstrap.group(eventLoopGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_REUSEADDR, true);
上网搜资料: 答案都大同小异,也没有考虑到自己代码层面有问题 总结网上的各个参数如下
注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
变更结果:
MaxUserPort 65534
TCPTimedWaitDelay 30
TcpNumConnections 0xfffffe
UseDomainNameDevolution 1
netsh int ipv4 show dynamicportrange tcp
执行结果:
协议 tcp 动态端口范围
---------------------------------
启动端口 : 1025
端口数 : 64510
虚拟内存空间分配自定义数据 4096~40960
以上数据更改后依然不行
最终发现 这个错误结果居然会变更 有两种结果 但是后来没有重现出来 就不上错误提示了
java.net.SocketException: No buffer space available (maximum connections reached?): bind
java.net.SocketException: No buffer space available (maximum connections reached?): connect
第一种报错 基本上是服务端最大端口限制出问题了
第二种报错 是客户端最大端口限制出问题了 最后根据错误提示找到 更改后代码片段 问题解决
static EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
()->{
ClientHandler clientHandler = new ClientHandler(client);
final Bootstrap bootstrap = new Bootstrap();
clientHandler.getClient().setEventLoopGroup(eventLoopGroup);
clientHandler.getClient().setBootstrap(bootstrap);
bootstrap.group(eventLoopGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_REUSEADDR, true);
}
结论:
1.当出现此类错误时不要盲目的修改, 先看清楚错误提示
2.重复创建EventLoopGroup会导致30倍左右当前tcp有效连接被占用
3.netstat -an |find /c "ESTABLISHED" 和 netstat -an |find /c "TIME_WAIT" 是个好东西
EventLoopGroup 相关解释: https://www.cnblogs.com/magexi/p/10222644.html