TCP客户端Socket如何立即释放端口?

showjim 2014-11-09 12:38:48
在做一个关于web负载均衡的压力测试的时候碰到一个问题。
测试采用的是单机测试,web服务器+3个负载均衡节点服务+客户端 都在同一台4核工作机上。
由于测试逻辑简单,1024个http客户端4s左右会吃光6W个端口,继续访问就会出现错误:由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作。错误的原因是Socket占用的端口没有被释放,需要等待20+s才能进行下一轮测试,很浪费时间。

需要说明的是,释放客户端端口不像服务器端口那样关闭Socket就可以了。客户端端口在Socket关闭之后处于Close_Wait状态,这个状态时间应该是由HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters下的TcpTimedWaitDelay键值决定的,但是这个值最小值是30s。
另外可以使用API函数SetTcpEntry强行关闭连接释放端口,但是某些操作系统由于UAC的原因需要提升为管理员权限,如果通过app.manifest设置管理员身份运行,会弹出一个提升权限的对话框,作为一个性能测试的Demo弹出这样一个框感觉有点吓人。

希望高人指点,如何在不需要用户参与的情况下把端口释放掉。需要具体测试代码的话可以到这里下载https://fastcsharp.codeplex.com/,测试项目为demo.loadBalancingTcpCommandWeb。
...全文
8726 47 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
47 条回复
切换为时间正序
请发表友善的回复…
发表回复
zp37 2016-12-28
  • 打赏
  • 举报
回复
做压力测试的小工具,也出现了同样的问题,终于找到组织了
showjim 2016-09-08
  • 打赏
  • 举报
回复
引用 45 楼 qq_22267193 的回复:
搞个计数器, 让socket绑定一次不就得了? 绑定一次了之后不用解除绑定,但是有计数器限制, 其只能绑定一次。
完全听不懂大神您说了些什么。。。
qq_安雍 2016-09-08
  • 打赏
  • 举报
回复
搞个计数器, 让socket绑定一次不就得了? 绑定一次了之后不用解除绑定,但是有计数器限制, 其只能绑定一次。
rayyu1989 2014-11-14
  • 打赏
  • 举报
回复
引用 43 楼 sbwwkmyd 的回复:
[quote=引用 42 楼 rayyu1989 的回复:]你最好排查下 这种情况下是否属于被动断开,看看服务端端口是否进入了等待状态
测试中没有发现对服务器端会有什么影响,受影响的仅仅是客户端。 如果客户端行为能够这么容易对服务器端造成影响,估计没有服务器会是稳定的了。[/quote]
showjim 2014-11-12
  • 打赏
  • 举报
回复
引用 32 楼 chzadm 的回复:
为什么不试试做几个TCP数据转发器,来增加数据发送或接收端口呢和数据量呢,好像网上有这类工具下载呢
不明白你说的TCP数据转发器具体是什么,有什么作用?
引用 34 楼 yalunwang123 的回复:
不知道对不对,CMD命令行里不是有 taskkill/pid 端口号来清除端口号,你可以把这种功能用C #写出来。可以试试
taskkill是用来杀进程的,对于服务端有效(而且正常情况下用不到),对于释放客户端端口号没有作用。
引用 36 楼 layershow 的回复:
[quote=引用 26 楼 sbwwkmyd 的回复:] [quote=引用 23 楼 layershow 的回复:]那是啥样的呢?所以等一会儿,哦,对方没有重复唠叨,那么我也可以关了
TCP的可靠仅仅是指,没有收到应答就重发。 现在的情况是客户端关闭,发出FIN,然后收到服务端回发的FIN,这种情况下客户端既不收也不发了,与可靠还有什么关系?[/quote] 所以后面的兄弟给你回复的是对的 Linger 正是干这个的,你可以在 Close 时强行关闭,那么就是要放弃其可靠性,丢弃协议栈缓存数据,另外 FIN 与其 ACK 本身也需要可靠性[/quote]指定Linger是在没有收发完毕的情况下调用Close对于收发数据的处理。
引用 31 楼 rayyu1989 的回复:
Wait状态没办法回避的 主动断开的一方一定会进入这个状态,端口复用可以玩下, ps 既然是测试工具 以管理员权限运行也没什么不妥,最多默认以普通权限运行,运行的程序识别当前权限,如果是普通权限 弹个msgbox 说明下管理员运行的原因,确认是否提权运行 如果用户选是 runas 一下,如果选否 退出程序
非常感谢你的提点,被动断开可用于解决这个问题。 不过稍有遗憾的是,我有个HTML标题抓取的组件同样存在这个问题,而且只能主动断开。当然这个是可以使用管理员权限启动的,但是要使用管理员权限就不方便自动部署与升级,需要手动操作。
layershow 2014-11-12
  • 打赏
  • 举报
回复
引用 26 楼 sbwwkmyd 的回复:
[quote=引用 23 楼 layershow 的回复:]那是啥样的呢?所以等一会儿,哦,对方没有重复唠叨,那么我也可以关了
TCP的可靠仅仅是指,没有收到应答就重发。 现在的情况是客户端关闭,发出FIN,然后收到服务端回发的FIN,这种情况下客户端既不收也不发了,与可靠还有什么关系?[/quote] 所以后面的兄弟给你回复的是对的 Linger 正是干这个的,你可以在 Close 时强行关闭,那么就是要放弃其可靠性,丢弃协议栈缓存数据,另外 FIN 与其 ACK 本身也需要可靠性
yalunwang123 2014-11-12
  • 打赏
  • 举报
回复
引用 34 楼 yalunwang123 的回复:
不知道对不对,CMD命令行里不是有 taskkill/pid 端口号来清除端口号,你可以把这种功能用C #写出来。可以试试
然后可以做一个winform来实现这个清除端口号,应该可以的
yalunwang123 2014-11-12
  • 打赏
  • 举报
回复
不知道对不对,CMD命令行里不是有 taskkill/pid 端口号来清除端口号,你可以把这种功能用C #写出来。可以试试
showjim 2014-11-12
  • 打赏
  • 举报
回复
引用 42 楼 rayyu1989 的回复:
你最好排查下 这种情况下是否属于被动断开,看看服务端端口是否进入了等待状态
测试中没有发现对服务器端会有什么影响,受影响的仅仅是客户端。 如果客户端行为能够这么容易对服务器端造成影响,估计没有服务器会是稳定的了。
rayyu1989 2014-11-12
  • 打赏
  • 举报
回复
引用 41 楼 sbwwkmyd 的回复:
引用 39 楼 rayyu1989 的回复:
任何时候服务端的主动断开都是不可取的 服务端是1对N 资源有限
我最后采用的是38#的方案,对于我的两个需求都合适。
你最好排查下 这种情况下是否属于被动断开,看看服务端端口是否进入了等待状态
showjim 2014-11-12
  • 打赏
  • 举报
回复
引用 39 楼 rayyu1989 的回复:
任何时候服务端的主动断开都是不可取的 服务端是1对N 资源有限
我最后采用的是38#的方案,对于我的两个需求都合适。
showjim 2014-11-12
  • 打赏
  • 举报
回复
引用 38 楼 layershow 的回复:
放弃其可靠性…… 也就是说直接用 RST 来关闭连接,而不是 FIN Socket 不可以 Shutdown,必须直接 Close 一旦触发了 FIN 去安全的关闭 Socket 那么 TIME_WAIT 是必然结果 Socket sock = new Socket(...); sock.SetSocketOption(Socket, Linger, new LingerOption(true, 0)); IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 10000); sock.bind(localEP); sock.Connect("http://www.csdn.net", 80); sock.Close();
测试结果确实和你说的一样,这种方案适合我的需求,两个问题都解决了。
rayyu1989 2014-11-12
  • 打赏
  • 举报
回复
引用 37 楼 sbwwkmyd 的回复:
[quote=引用 32 楼 chzadm 的回复:]为什么不试试做几个TCP数据转发器,来增加数据发送或接收端口呢和数据量呢,好像网上有这类工具下载呢
不明白你说的TCP数据转发器具体是什么,有什么作用?
引用 34 楼 yalunwang123 的回复:
不知道对不对,CMD命令行里不是有 taskkill/pid 端口号来清除端口号,你可以把这种功能用C #写出来。可以试试
taskkill是用来杀进程的,对于服务端有效(而且正常情况下用不到),对于释放客户端端口号没有作用。
引用 36 楼 layershow 的回复:
[quote=引用 26 楼 sbwwkmyd 的回复:] [quote=引用 23 楼 layershow 的回复:]那是啥样的呢?所以等一会儿,哦,对方没有重复唠叨,那么我也可以关了
TCP的可靠仅仅是指,没有收到应答就重发。 现在的情况是客户端关闭,发出FIN,然后收到服务端回发的FIN,这种情况下客户端既不收也不发了,与可靠还有什么关系?[/quote] 所以后面的兄弟给你回复的是对的 Linger 正是干这个的,你可以在 Close 时强行关闭,那么就是要放弃其可靠性,丢弃协议栈缓存数据,另外 FIN 与其 ACK 本身也需要可靠性[/quote]指定Linger是在没有收发完毕的情况下调用Close对于收发数据的处理。
引用 31 楼 rayyu1989 的回复:
Wait状态没办法回避的 主动断开的一方一定会进入这个状态,端口复用可以玩下, ps 既然是测试工具 以管理员权限运行也没什么不妥,最多默认以普通权限运行,运行的程序识别当前权限,如果是普通权限 弹个msgbox 说明下管理员运行的原因,确认是否提权运行 如果用户选是 runas 一下,如果选否 退出程序
非常感谢你的提点,被动断开可用于解决这个问题。 不过稍有遗憾的是,我有个HTML标题抓取的组件同样存在这个问题,而且只能主动断开。当然这个是可以使用管理员权限启动的,但是要使用管理员权限就不方便自动部署与升级,需要手动操作。[/quote] 任何时候服务端的主动断开都是不可取的 服务端是1对N 资源有限
layershow 2014-11-12
  • 打赏
  • 举报
回复
放弃其可靠性…… 也就是说直接用 RST 来关闭连接,而不是 FIN Socket 不可以 Shutdown,必须直接 Close 一旦触发了 FIN 去安全的关闭 Socket 那么 TIME_WAIT 是必然结果 Socket sock = new Socket(...); sock.SetSocketOption(Socket, Linger, new LingerOption(true, 0)); IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 10000); sock.bind(localEP); sock.Connect("http://www.csdn.net", 80); sock.Close();
  • 打赏
  • 举报
回复
通过自己开发和封装HttpWebRequest类,通过为 TcpClient.Client 绑定端口(以及端口复用) 或许用几十个端口就能模拟你的十几万个http请求了,因为 http 很慢,一旦一个消息收到响应之后,客户端不关闭而是用处理其它消息。
  • 打赏
  • 举报
回复
没什么好办法。除非你自己使用 TcpClient 封装一个“http客户端”类(不用.net类库中现成的),重复使用本地端口、而不关闭。
足球中国 2014-11-11
  • 打赏
  • 举报
回复
CloseHandle这个可以嘛??
  • 打赏
  • 举报
回复
引用 32 楼 chzadm 的回复:
为什么不试试做几个TCP数据转发器,来增加数据发送或接收端口呢和数据量呢,好像网上有这类工具下载呢
lz 需要在10几分钟内用1千万个端口(或者等价的东西)。
帮帮你我她 2014-11-11
  • 打赏
  • 举报
回复
为什么不试试做几个TCP数据转发器,来增加数据发送或接收端口呢和数据量呢,好像网上有这类工具下载呢
showjim 2014-11-11
  • 打赏
  • 举报
回复
周二了,再看看
加载更多回复(27)

111,088

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧