LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

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

admin
2017年4月12日 1:29 本文热度 25192
在做一个关于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。

该文章在 2017/4/12 1:29:55 编辑过

全部评论12

admin
2017年4月12日 1:30
发现连接数超某数时,及时清除不用套接字子线程,服务器与客户端均可设超时强制关闭
Visual Basic code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    ''及时清除不用的子线程。
    Private Sub dogthread(ByVal Tzobj As System.ObjectByVal 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

该评论在 2017/4/12 1:30:48 编辑过
admin
2017年4月12日 1:31
Visual Basic code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    ''及时清除不用的子线程。
    Private Sub dogthread(ByVal Tzobj As System.ObjectByVal 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

该评论在 2017/4/12 1:31:21 编辑过
admin
2017年4月12日 1:31
谢谢回复,真不是这么简单的事。你可以试试能不能在30s之内创建>65536个客户端连接。

该评论在 2017/4/12 1:31:56 编辑过
admin
2017年4月12日 1:32
我对tcp研究的不是那么深.. 请问你这个6W多连接  是长连接没有断开的?

不是吧 client的端口也没这么多..

如果是ope send close dispose的话 感觉还差不多可以..

否则这也不叫长连接了啊.....

难道你的意思 本地client使用了5000端口连接 然后这5000还可以个下一个client用?

不存在啊..那么你2个client 服务器如何找到客户端...

该评论在 2017/4/12 1:32:27 编辑过
admin
2017年4月12日 1:33
1
2
3
4
5
6
            TcpClient c = new TcpClient();
            c.Connect(IPAddress.Parse("x"), o);
            c.Client.Send(by);
            c.Client.Shutdown(SocketShutdown.Both);
            c.Client.Close();
            c.Close();

这虽然是tcp_client但是发了就没了.....具体我还真没测试过..不知道我想的是不是跟你想的一样..

该评论在 2017/4/12 1:33:04 编辑过
admin
2017年4月12日 1:33
长连接就不是30s的问题了,短连接,用完立即Shutdown+Close,Dispose也是没用的。 我这里可以用到6W+端口,这个数量与范围也可以修改注册表。
测试中同时存在的client只有1024,也就是1024并发。
端口在Socket关闭之后是可以给其它Socket使用的,不过现在的问题就是要等待30s。
引用 5 楼 diaodiaop 的回复:
C# code
?
1
2
3
4
5
6
            TcpClient c = new TcpClient();
            c.Connect(IPAddress.Parse("x"), o);
            c.Client.Send(by);
            c.Client.Shutdown(SocketShutdown.Both);
            c.Client.Close();
            c.Close();
这虽然是tcp_client但是发了就没了.....具体我还真没测试过..不知道我想的是不是跟你想的一样..
你在Close之后的30s内应该都能用netstat看到这个连接处于Close_Wait状态,并没有释放端口。

该评论在 2017/4/12 1:33:28 编辑过
admin
2017年4月12日 1:34
假设本地0-65536都可用
也就是 
C# code
?
1
2
3
4
5
6
7
for 30000
           TcpClient c = new TcpClient();
            c.Connect(IPAddress.Parse("x"), o);
            c.Client.Send(by);
            c.Client.Shutdown(SocketShutdown.Both);
            c.Client.Close();
            c.Close();
这个情况下..使用了0-30000这个3W个port..
30s之内 这些port是不能重复使用的..
假设在30s之内已经到了65535 就死掉了..但是理想中希望的是  前面的端口已经释放了 还可以用 是吧..
这个还真没研究过..一般都是玩server.client哪有这么多啊..
如果你只是要测试server的压力 我都用别人的软件测试并发. 如果自己写好像就是什么线程池吧....
就是先建立连接不发..然后..一起发送...

该评论在 2017/4/12 1:34:16 编辑过
admin
2017年4月12日 1:34
是这样的,压力测试工具都有这个问题。要么达不到这个吞吐量,要么需要管理员身份运行。 如果仅仅是自己用没有什么问题,但是作为一个Demo要以管理员身份运行,有点过分,不合适。

该评论在 2017/4/12 1:34:39 编辑过
admin
2017年4月12日 1:35
服务器端可以限制连接总数,超过总数的,拒绝连接即可,保持连接总数不超过mou值
Visual Basic code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
          If i < 100 Then ''否则,线程已满,忙。。 不接收新线程了
                    mySocket(i) = socktep
                    socktep = Nothing
                    Try
                        myThread(i) = New Thread(AddressOf WaitData)  ''建立新的线程--为每个客户端创建一个线程
                        myThread(i).IsBackground = True
                        Threadnumber = i    '' 开启的当前线程号数
                        myThread(i).Start()
                    Catch
                        IsRun(i) = False   ''改标志,以便侦听时,消除此出错线程
                    End Try
                Else
                    ''人数已满,稍后连接!--关闭第100个套接字
                    If mySocket(100) Is Nothing Then
                        mySocket(100) = socktep
                        socktep = Nothing
                        Try
                            Dim msg1 As String "服务器忙,稍后连接!"
                            Call sendmsg(msg1, 100)   ''把msg1内的消息内容 发送出去
                            msg1 = "Exit"
                            Call sendmsg(msg1, 100)
                        Catch
                        End Try
                        Try
                            System.Threading.Thread.Sleep(1)
                            mySocket(100).Shutdown(SocketShutdown.Both)
                        Catch
                        End Try
                        Try
                            System.Threading.Thread.Sleep(2)
                            mySocket(100).Close()
                            mySocket(100) = Nothing
                        Catch
                        End Try
                    Else
                        Try
                            Dim msg As Byte() = Encoding.UTF8.GetBytes("Exit")
                            Dim bytesSent As Integer = socktep.Send(msg)
                        Catch
                        End Try
                        Try
                            System.Threading.Thread.Sleep(1)
                            socktep.Shutdown(SocketShutdown.Both)
                        Catch
                        End Try
                        Try
                            System.Threading.Thread.Sleep(2)
                            socktep.Close()
                            socktep = Nothing
                        Catch
                        End Try
                        If dogrunBZ(100) = True Then
                            dogrunBZ(100) = False    ''关闭线程的相应异步调用,正在运行时=true  ''防止重复运行
                        End If
                        Try
                            mySocket(100).Shutdown(SocketShutdown.Both)
                        Catch
                        End Try
                        Try
                            System.Threading.Thread.Sleep(2)
                            mySocket(100).Close()
                            mySocket(100) = Nothing
                        Catch
                        End Try
                    End If
                End If

该评论在 2017/4/12 1:35:09 编辑过
admin
2017年4月12日 1:35
没什么好办法。除非你自己使用 TcpClient 封装一个“http客户端”类(不用.net类库中现成的),重复使用本地端口、而不关闭。

该评论在 2017/4/12 1:35:39 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved