说明
在windows中使用go实现了一个服务器压力测试工具,使用的TCP协议,在调试期间,出现问题如下
Only one usage of each socket address (protocol/network address/por
t) is normally permitted.
从字面上来看是告诉我们是socket被复用了。在网上查了原因之后发现是套接字用完了,也就是同时建立的TCP连接量超过了系统的限制。但是经过验证,发现其实并不是因为同时建立的TCP连接过多造成的。
问题分析
在我的测试工具中,我开启了20个协程去建立TCP连接,发送数据包,再关闭连接,并重复这个过程,也就是说同时也就最多建立20个TCP连接,远远小于windows中的tcp同时建立连接数的限制,并不可能出现TCP连接建立量超过系统限制的原因。那么又会是什么原因呢?
原来影响TCP连接建立数量的因素不止是最大建立连接数决定的。还有一系列的参数影响TCP连接的建立。在windows的注册表中的HKEY_LOCAL_MACHINE \System \CurrentControlSet \services \Tcpip \Parameters中,
最大TCB 数量
系统为每个TCP 连接分配一个TCP 控制块(TCP control block or TCB),这个控制块用于缓存TCP连接的一些参数(源端口、目的端口、目的ip、序号、应答序号、对方窗口大小、己方窗口大小、tcp状态、tcp输入/输出队列、应用层输出队列、tcp的重传有关变量等),每个TCB需要分配 0.5 KB的pagepool 和 0.5KB 的Non-pagepool,也就说,每个TCP连接会占用 1KB 的系统内存。
系统的最大TCB数量由如下注册表设置决定
[HKEY_LOCAL_MACHINE \System \CurrentControlSet \Services \Tcpip \Parameters]
MaxFreeTcbs = 2000 (Default = RAM dependent, but usual Pro = 1000, Srv=2000)
这里也就表示最大可同时创建两千个TCP连接。
但是通过调整注册表中的以下参数可以改变这个值。
MaxUserPort = 65534 (Decimal)
MaxHashTableSize = 65536 (Decimal)
MaxFreeTcbs = 16000 (Decimal)
把这几项都调到最大。即可把TCP同时建立数扩大到16000。此时确实发现,这个报错会出现在当tcp连接建立到16000左右的时候。但是依然不是同时建立这么多连接,每次建立完都有关闭tcp。
猜想
tcb控制块并不是断开TCP连接后直接释放,而是要等待TCP连接time_wait时间之后再释放。
验证
重启服务器,再次使用测试工具进行测试。
如图所示,当短时间内建立TCP连接数到16000左右的时候再次出现问题。
关闭测试工具,等待1分钟后,启动测试工具。依然报错。
关闭测试工具,在等待1分钟,也就是过了TCP默认的time_wait时间,再启动测试工具,不再报错又可以重新建立连接。
验证tcb控制块并不是断开TCP连接后直接释放,而是要等待TCP连接time_wait时间之后再释放。