SuperSocket icon indicating copy to clipboard operation
SuperSocket copied to clipboard

急救!远程主机强迫关闭了一个现有的连接。

Open loveyeguo opened this issue 1 year ago • 20 comments

此代码:

   private async Task KeepAccept(Socket listenSocket)
   {
       while (!_cancellationTokenSource.IsCancellationRequested)
       {
           try
           {
               var client = await listenSocket.AcceptAsync().ConfigureAwait(false);
               OnNewClientAccept(client);
           }
           catch (Exception e)
           {
               if (e is ObjectDisposedException || e is NullReferenceException)
                   break;
               
               if (e is SocketException se)
               {
                   var errorCode = se.ErrorCode;

                   //The listen socket was closed
                   if (errorCode == 125 || errorCode == 89 || errorCode == 995 || errorCode == 10004 || errorCode == 10038)
                   {
                       break;
                   }
               }
               
               _logger.LogError(e, $"Listener[{this.ToString()}] failed to do AcceptAsync");
               continue;
           }
       }

       _stopTaskCompletionSource.TrySetResult(true);
   } 

目前客户端有200多个,运行几分钟后,程序一直报错: Listener[Ip=Any, Port=1799, Security=None, Path=, BackLog=0, NoDelay=False] failed to do AcceptAsync远程主机强迫关闭了一个现有的连接。 此时测试程序端口仍然能够正常连接并传输数据,只是一直报错而已。但运行5-6小时后,新的客户端将无法再次连接。 我使用老版1.6版本,同样监听此端口,报错也有,但是运行一天以后,新的客户端依然可以正常连接。 请问如何解决? 谢谢大佬!

loveyeguo avatar Dec 16 '24 04:12 loveyeguo

会不会是你电脑问题

wj8400684 avatar Dec 18 '24 01:12 wj8400684

不会

loveyeguo avatar Dec 18 '24 03:12 loveyeguo

我已经测试了好几遍了,确定是supersocket程序本身bug。

loveyeguo avatar Dec 18 '24 03:12 loveyeguo

建议写个最小demo复现

wj8400684 avatar Dec 18 '24 05:12 wj8400684

直接用源码侦听就复现了,没有写任何逻辑代码,就侦听两个端口。运行5-6个小时,新的客户端无法再次连接。现在我暂时修复了这个bug : 修改代码如下:

 public bool Start()
        {
            var options = Options;

            try
            {
                if (options.Security != SslProtocols.None && options.CertificateOptions != null)
                {
                    options.CertificateOptions.EnsureCertificate();
                }

                var listenEndpoint = options.GetListenEndPoint();
                var listenSocket = _listenSocket = new Socket(listenEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
                listenSocket.ReceiveTimeout = 10000; // 设置为10秒
                listenSocket.SendTimeout = 10000; // 设置为10秒
                listenSocket.LingerState = new LingerOption(false, 0);

                if (options.NoDelay)
                    listenSocket.NoDelay = true;
                
                listenSocket.Bind(listenEndpoint);
                listenSocket.Listen(options.BackLog);

                IsRunning = true;

                _cancellationTokenSource = new CancellationTokenSource();

                KeepAccept(listenSocket).DoNotAwait();
                return true;
            }
            catch (Exception e)
            {
                _logger.LogError(e, $"The listener[{this.ToString()}] failed to start.");
                return false;
            }
        }

主要就是要在原有代码上增加如下三行:

listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
                listenSocket.ReceiveTimeout = 10000; // 设置为10秒
                listenSocket.SendTimeout = 10000; // 设置为10秒

loveyeguo avatar Dec 18 '24 05:12 loveyeguo

原有bug复现大致方法: 让大量tcp客户端不断连接然后断开,tcp服务端在运行几个小时后无法再次连接。

loveyeguo avatar Dec 18 '24 05:12 loveyeguo

那这跟supersocket没啥关系呀 应该是你端口耗尽了

wj8400684 avatar Dec 18 '24 05:12 wj8400684

不是啊,诶,你没完全看我写的。 我都说这么详细了。同一台服务器,用1.6版本,没有问题。用最新版本,出现问题。 目前加了那三行代码,暂时没有出现问题。 麻烦完整看一遍我的描述!

loveyeguo avatar Dec 18 '24 05:12 loveyeguo

解决就行

wj8400684 avatar Dec 18 '24 06:12 wj8400684

我这只是临时解决办法,实际情况错误一直在报,我也不懂啥时候就崩溃了,请问你也是联合开发作者吗? 有空可以关注下这个问题!

loveyeguo avatar Dec 18 '24 06:12 loveyeguo

Please provide the source code of the demo, including both client and server code, and push to your own git repository(maybe you can create a new git repository under your GitHub account)

chucklu avatar Dec 18 '24 09:12 chucklu

模拟不了客户端,客户端是rtu采集模块,200多个,我不清楚客户端做了什么操作,就会引起服务器的上述错误。

loveyeguo avatar Dec 19 '24 00:12 loveyeguo

总而言之,只要引起服务端上诉代码报错: 远程主机强迫关闭现有连接,其他服务端代码不要任何逻辑,只负责侦听端口。即可重现bug

loveyeguo avatar Dec 19 '24 00:12 loveyeguo

写个简易demo复现

wj8400684 avatar Dec 19 '24 00:12 wj8400684

我也是同样的现象 和你一摸一样

fangqifan avatar Dec 25 '24 06:12 fangqifan

我不清楚是否和windows系统版本或者framework版本有关 我的socket服务器之前运行在windows server 2012和.net framework 4.6.1环境中 一直良好运行 但最近迁移至windows server 2022和.net framework 4.8 和你出现了一样的问题 不同的在于我使用的Supersocket版本为1.6.6.1

fangqifan avatar Dec 25 '24 07:12 fangqifan

我的程序连接了大概20台设备 设备通过移动网络连接服务器 有几台设备地处偏远 信号不稳定 会出现断连 然后自动重连的情况 运行大概20个小时不到就会出现上述情况

fangqifan avatar Dec 25 '24 07:12 fangqifan

我怀疑在你的场景下,发生了一下错误,然后listener就不再继续监听了。

//The listen socket was closed if (errorCode == 125 || errorCode == 89 || errorCode == 995 || errorCode == 10004 || errorCode == 10038) { break; }

kerryjiang avatar Dec 27 '24 20:12 kerryjiang

@loveyeguo 出现这种情况的时候进程是不是挂掉了?

我增加了log,建议从myget上拿最新代码重现这个问题,通过log再来找到导致这个问题的原因。

kerryjiang avatar Dec 27 '24 23:12 kerryjiang

@loveyeguo 出现这种情况的时候进程是不是挂掉了?

我增加了log,建议从myget上拿最新代码重现这个问题,通过log再来找到导致这个问题的原因。

不是,并没有进入break,我已经打了日志,程序还是在监听的,而且运行十几个小时后,程序仍然在运行,但是已经无法建立新的连接,而旧连接还有残余2-3个存在。 你看下我前面的记录,已经修改了这个bug。虽然一直报错,但是目前运行一周多了,没有出现无法建立新连接的情况。解决办法就是增加下面代码:

listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
                listenSocket.ReceiveTimeout = 10000; // 设置为10秒
                listenSocket.SendTimeout = 10000; // 设置为10秒

但为什么这么加上就可以了,我自己也没有完全明白。大佬有空可以查查。

loveyeguo avatar Dec 30 '24 05:12 loveyeguo