TCP多次重复断连后接收不到客户端的连接请求了

悠然的二货 2020-08-12 02:47:08
代码是参考https://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs(v=vs.110).aspx写的

服务端Listen数2000
找了一个TCP客户端测试工具创建了2000个客户端同时连接服务端并发送数据,过几秒钟后全部断开,这样反复7、8次后续客户端就连接不上服务端了。
netstat 里看到服务端还是处于监听状态的 TCP 127.0.0.1:20000 0.0.0.0:0 LISTENING

请问下该怎么排查这个问题?或者说会有哪些操作会导致这个问题?
...全文
3010 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
悠然的二货 2020-08-14
  • 打赏
  • 举报
回复
引用 14 楼 datafansbj 的回复:
[quote=引用 12 楼 悠然的二货 的回复:][quote=引用 6 楼 datafansbj 的回复:]TCP 连接会话在断开后,主动断开的一方会进入 timewait 状态,持续 120-240 秒(依据操作系统),在此期间这个会话的源端口号(随机端口)不可用,直到该端口号被释放(参见《TCP-IP详解》一书)。你的客户端建立 TCP 连接太频繁了,压力测试应使用多个客户端机器来模拟,而不是一个。 可以使用 netstat 命令查看网络会话状态。
客户端关闭后,我用netstat -ano看到服务端处于监听状态,然后列表里是没有客户端。这连接应该是断干净了吧?[/quote] 你应该看客户端,不是服务端。[/quote]客户端和服务端是同一台电脑,客户端关闭后netstat里没有客户端
datafansbj 2020-08-14
  • 打赏
  • 举报
回复
引用 12 楼 悠然的二货 的回复:
[quote=引用 6 楼 datafansbj 的回复:]TCP 连接会话在断开后,主动断开的一方会进入 timewait 状态,持续 120-240 秒(依据操作系统),在此期间这个会话的源端口号(随机端口)不可用,直到该端口号被释放(参见《TCP-IP详解》一书)。你的客户端建立 TCP 连接太频繁了,压力测试应使用多个客户端机器来模拟,而不是一个。

可以使用 netstat 命令查看网络会话状态。
客户端关闭后,我用netstat -ano看到服务端处于监听状态,然后列表里是没有客户端。这连接应该是断干净了吧?[/quote]

你应该看客户端,不是服务端。
github_36000833 2020-08-13
  • 打赏
  • 举报
回复
如果CloseClientSocket(e);会抛异常,那就类似如下代码?
private void CloseClientSocket(SocketAsyncEventArgs e)
{
    AsyncUserToken token = e.UserToken as AsyncUserToken;

    // close the socket associated with the client
    try
    {
        token.Socket.Shutdown(SocketShutdown.Send);
        token.Socket.Close();
    }
    // throws if client process has already closed
    catch (Exception) { }
    finally  // <----
    {
        // decrement the counter keeping track of the total number of clients connected to the server
        Interlocked.Decrement(ref m_numConnectedSockets);

        // Free the SocketAsyncEventArg so they can be reused by another client
        m_readWritePool.Push(e);

        m_maxNumberAcceptedClients.Release();
    }
    Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets);
}
github_36000833 2020-08-13
  • 打赏
  • 举报
回复
类似如此? try { } catch(...) { CloseClientSocket(e); } 或者如果逻辑适合,就放finally块下?
悠然的二货 2020-08-13
  • 打赏
  • 举报
回复
引用 3 楼 github_36000833 的回复:
你可以先用工具,或程序里自我检查一些调试数据,比如内存占用,线程数量,线程池下的工作线程数和IOCP线程数,等等。 还可以考虑,把m_maxNumberAcceptedClients换成SemaphorSlim,它支持查看当前信号占用数。 如果信号占用数没有被释放,就可能导致m_maxNumberAcceptedClients.WaitOne();阻塞,从而导致没有继续下一个接收,客户端就连接不上服务端了。 如果ProcessReceive和ProcessSend里面有代码抛出异常,就会导致CloseClientSocket(e);没有机会得到调用,就可能导致该连接的信号占用数就没有被释放。
确实是这个信号量的问题,我刚刚用SemaphoreSlim看了下,每一次重连都会增加占用数。ProcessReceive和ProcessSend似乎没有抛异常。查了下是CloseClientSocket里的token.Socket.Close();抛了异常导致信号量没释放,token=null。当客户端数量大于服务端监听的数量时好像就会出现这个问题,在ProcessAccept里AcceptSocket.RemoteEndPoint也是null,抛了异常导致信号量没释放。请教一下在ProcessAccept里AcceptSocket.RemoteEndPoint=null的情况下怎么做处理比较合适?直接return也会导致信号量没释放
datafansbj 2020-08-13
  • 打赏
  • 举报
回复
TCP 连接会话在断开后,主动断开的一方会进入 timewait 状态,持续 120-240 秒(依据操作系统),在此期间这个会话的源端口号(随机端口)不可用,直到该端口号被释放(参见《TCP-IP详解》一书)。你的客户端建立 TCP 连接太频繁了,压力测试应使用多个客户端机器来模拟,而不是一个。

可以使用 netstat 命令查看网络会话状态。
悠然的二货 2020-08-13
  • 打赏
  • 举报
回复
引用 8 楼 github_36000833 的回复:
类似如此? try { } catch(...) { CloseClientSocket(e); } 或者如果逻辑适合,就放finally块下?
我在ProcessAccept里最前面加了判断
if (e.AcceptSocket.RemoteEndPoint == null)
                {
                    m_maxNumberAcceptedClients.Release();
                    StartAccept(e);
                    return;
                }
试了几次似乎没什么问题.....我没怎么搞明白当一个异步连接触发时为什么有时候RemoteEndPoint是null,这种情况出现在客户端同时连接数大于服务端监听时。然后同时关闭全部客户端时会出现RemoteEndPoint是null
悠然的二货 2020-08-13
  • 打赏
  • 举报
回复
引用 6 楼 datafansbj 的回复:
TCP 连接会话在断开后,主动断开的一方会进入 timewait 状态,持续 120-240 秒(依据操作系统),在此期间这个会话的源端口号(随机端口)不可用,直到该端口号被释放(参见《TCP-IP详解》一书)。你的客户端建立 TCP 连接太频繁了,压力测试应使用多个客户端机器来模拟,而不是一个。 可以使用 netstat 命令查看网络会话状态。
客户端关闭后,我用netstat -ano看到服务端处于监听状态,然后列表里是没有客户端。这连接应该是断干净了吧?
悠然的二货 2020-08-13
  • 打赏
  • 举报
回复
引用 5 楼 水边2 的回复:
服务端看下 netstat各种状态的连接数据量, 客户端也用netstat看下连接状态, 怀疑连接占满了
我用netstat -ano 看服务端处于监听状态,然后客户端一个都没
  • 打赏
  • 举报
回复
我估计是你客户端全部断开后 服务器端得连接 仍然没有断开, 你可以尝试定义一个断开连接的请求,通知服务端销毁连接
游北亮 2020-08-12
  • 打赏
  • 举报
回复
服务端看下 netstat各种状态的连接数据量, 客户端也用netstat看下连接状态, 怀疑连接占满了
八爻老骥 2020-08-12
  • 打赏
  • 举报
回复
服务端要做断开检测的,比如写入异常,就表示断开了,此时要把服务端连接释放掉,否则会影响后边的连接。
github_36000833 2020-08-12
  • 打赏
  • 举报
回复
你可以先用工具,或程序里自我检查一些调试数据,比如内存占用,线程数量,线程池下的工作线程数和IOCP线程数,等等。 还可以考虑,把m_maxNumberAcceptedClients换成SemaphorSlim,它支持查看当前信号占用数。 如果信号占用数没有被释放,就可能导致m_maxNumberAcceptedClients.WaitOne();阻塞,从而导致没有继续下一个接收,客户端就连接不上服务端了。 如果ProcessReceive和ProcessSend里面有代码抛出异常,就会导致CloseClientSocket(e);没有机会得到调用,就可能导致该连接的信号占用数就没有被释放。
qq_29817615 2020-08-12
  • 打赏
  • 举报
回复
看下是不是有大量 没有完全断开的连接
小白卟白 2020-08-12
  • 打赏
  • 举报
回复
服务端也没有做,客户端断开处理。socket服务端在客户端断开后5-10中还是处于连接状态。所以导致2000客户端重连时会失败!

110,526

社区成员

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

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

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