TCP客户端Socket怎么样立即释放端口

.Net技术 码拜 8年前 (2016-09-26) 4495次浏览
在做一个关于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。
解决方案

5

发现连接数超某数时,及时清除不用套接字子线程,服务器与客户端均可设超时强制关闭

    "及时清除不用的子线程。
    Private Sub dogthread(ByVal Tzobj As System.Object, ByVal e As System.EventArgs)
        dogrunBZ(Tzobj) = True                                                              "正在运行时,防止重复运行
        Try
            mySocket(Tzobj).Shutdown(SocketShutdown.Receive)   "关闭套接字接收
            "mySocket(Tzobj).Shutdown(SocketShutdown.Both)        "组态王对此条支持不好
        Catch
        End Try
        Try
            mySocket(Tzobj).Close()                                                          "引发子线程立即异常,中断子线程循环
        Catch
        End Try
        Try
            myThread(Tzobj).Abort()                                                          "中止某个线程,销毁这些线程,需要很多时间!
            myThread(Tzobj).Join(300)                                                     "等待300毫秒,超时也终止,防止不出来
        Catch
        End Try
        Try
            mySocket(Tzobj) = Nothing                                                     "防止组态王响应没那么快!
        Catch
        End Try
        GC.Collect()
        dogrunBZ(Tzobj) = False                                                             "运行完毕标志 
    End Sub

5

    "及时清除不用的子线程。
    Private Sub dogthread(ByVal Tzobj As System.Object, ByVal e As System.EventArgs)
        dogrunBZ(Tzobj) = True                                 "正在运行时,防止重复运行
        Try
            mySocket(Tzobj).Shutdown(SocketShutdown.Receive)   "关闭套接字接收
            "mySocket(Tzobj).Shutdown(SocketShutdown.Both)     "组态王对此条支持不好
        Catch
        End Try
        Try
            mySocket(Tzobj).Close()                            "引发子线程立即异常,中断子线程循环
        Catch
        End Try
        Try
            myThread(Tzobj).Abort()                            "中止某个线程,销毁这些线程,需要很多时间!
            myThread(Tzobj).Join(300)                          "等待300毫秒,超时也终止,防止不出来
        Catch
        End Try
        Try
            mySocket(Tzobj) = Nothing                          "防止组态王响应没那么快!
        Catch
        End Try
        GC.Collect()
        dogrunBZ(Tzobj) = False                                "运行完毕标志 
    End Sub

5

引用:

这是 TCP 协议的问题哦,原因是它是一个“可靠的”家伙。

就是对方说”本人要关啦“,你说”哦,知道了“,万一”哦,知道了“这句话对方没听见呢,真的是个”可靠的“家伙吧,想得真”周到“

5

引用:
Quote: 引用:

CloseHandle这个可以嘛?

没有用。

引用:

没什么好办法。除非你本人使用 TcpClient 封装一个“http客户端”类(不用.net类库中现成的),重复使用本地端口、而不关闭。

直接用的Socket,测试而已都不用封装。

引用:

通过本人开发和封装HttpWebRequest类,通过为 TcpClient.Client 绑定端口(以及端口复用) 或许用几十个端口就能模拟你的十几万个http请求了,原因是 http 很慢,一旦一个消息收到响应之后,客户端不关闭而是用处理其它消息。

谢谢回复,端口复用的前提是远程EndPoint不同,而压力测试的远程EndPoint都是相同的,所以端口复用是不行的。
另外http本身并不比TCP慢多少,区别就是数据量大一点点,解析数据的方式不同;当然你假如说的是IIS/ASP.NET这种web应用,那是应用本人慢。

没看到你的测试的东西。没办法试。
return diantou.dataProxy.questionTopic.getLinkIds(id)
.getArray(value => diantou.dataProxy.question.get(value))
.getHash(value => value.bestAnswerId)
.getArray(value => diantou.dataProxy.answer.get(value))
.getFind(value => value != null)
这些是c# 新特性吧。看不懂。

1

引用:
Quote: 引用:

这是 TCP 协议的问题哦,原因是它是一个“可靠的”家伙。
就是对方说”本人要关啦“,你说”哦,知道了“,万一”哦,知道了“这句话对方没听见呢,真的是个”可靠的“家伙吧,想得真”周到“

TCP的可靠可不是这样子的,真要这样的话,双方永远都关不了了。

TCP客户端Socket怎么样立即释放端口那是啥样的呢?所以等一会儿,哦,对方没有重复唠叨,那么本人也可以关了

10

引用:
Quote: 引用:

那是啥样的呢?所以等一会儿,哦,对方没有重复唠叨,那么本人也可以关了

TCP的可靠仅仅是指,没有收到应答就重发。
现在的情况是客户端关闭,发出FIN,然后收到服务端回发的FIN,这种情况下客户端既不收也不发了,与可靠还有什么关系?

可以强制终止TCP的可靠性的。在不进行设置的情况下,close是会延时释放资源,并尝试把挂起在套接字上的数据或其他发送或接收。
下面是MSDN:
当 LingerState 属性更改 Close 方法的行为方式。 假如设置此属性,将修改 Winsock 可重置的连接的条件。 基于 IP 协议行为还是会出现连接重置。
当仍然要发送数据时,此属性控制面向连接的连接在对 Close 调用后仍保持打开的时间长度。

且LingerState的默认值是false,这时close后会“尝试发送挂起的数据,直到默认 IP 协议超时过期。”
详见:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.lingerstate.aspx
怎么样这也不能的话,那只能深入研究close方法的实现了

5

引用:
Quote: 引用:
Quote: 引用:

那是啥样的呢?所以等一会儿,哦,对方没有重复唠叨,那么本人也可以关了

TCP的可靠仅仅是指,没有收到应答就重发。
现在的情况是客户端关闭,发出FIN,然后收到服务端回发的FIN,这种情况下客户端既不收也不发了,与可靠还有什么关系?

可以强制终止TCP的可靠性的。在不进行设置的情况下,close是会延时释放资源,并尝试把挂起在套接字上的数据或其他发送或接收。
下面是MSDN:
当 LingerState 属性更改 Close 方法的行为方式。 假如设置此属性,将修改 Winsock 可重置的连接的条件。 基于 IP 协议行为还是会出现连接重置。
当仍然要发送数据时,此属性控制面向连接的连接在对 Close 调用后仍保持打开的时间长度。

且LingerState的默认值是false,这时close后会“尝试发送挂起的数据,直到默认 IP 协议超时过期。”
详见:http://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.lingerstate.aspx
怎么样这也不能的话,那只能深入研究close方法的实现了

就是不知道没有挂起数据的时候会不会立即释放所占资源

5

怎么样你设置TCPIP的超时时间可以的话,设置LingerState 为true,LingerState.LingerTime为0的话应该也可以吧,相当于不采用系统默认的TCPIP超时时间

200

Wait状态没办法回避的  主动断开的一方一定会进入这个状态,端口复用可以玩下, ps  既然是测试工具 以管理员权限运行也没什么不妥,最多默认以普通权限运行,运行的程序识别当前权限,假如是普通权限 弹个msgbox 说明下管理员运行的原因,确认能否提权运行 假如用户选是 runas 一下,假如选否 退出程序

5

为什么不试试做几个TCP数据转发器,来增加数据发送或接收端口呢和数据量呢,好像网上有这类工具下载呢

5

引用:

为什么不试试做几个TCP数据转发器,来增加数据发送或接收端口呢和数据量呢,好像网上有这类工具下载呢

lz 需要在10几分钟内用1千万个端口(或等价的东西)。

1

不知道对不对,CMD命令行里不是有  taskkill/pid  端口号来清除端口号,你可以把这种功能用C #写出来。可以试试

1

引用:

不知道对不对,CMD命令行里不是有  taskkill/pid  端口号来清除端口号,你可以把这种功能用C #写出来。可以试试

然后可以做一个winform来实现这个清除端口号,应该可以的

1

引用:
Quote: 引用:

那是啥样的呢?所以等一会儿,哦,对方没有重复唠叨,那么本人也可以关了

TCP的可靠仅仅是指,没有收到应答就重发。
现在的情况是客户端关闭,发出FIN,然后收到服务端回发的FIN,这种情况下客户端既不收也不发了,与可靠还有什么关系?

所以后面的兄弟给你回复的是对的 Linger 正是干这个的,你可以在 Close 时强行关闭,那么就是要放弃其可靠性,丢弃协议栈缓存数据,另外 FIN 与其 ACK 本身也需要可靠性


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明TCP客户端Socket怎么样立即释放端口
喜欢 (0)
[1034331897@qq.com]
分享 (0)