TcpClient 上的堆栈溢出(递归)

Stack Overflow on TcpClient (Recursion)

由于重复调用new,以下代码如果保持原样可能会产生堆栈溢出异常:

async void Connect()
{
    try 
    {
        client = new TcpClient(ip, port);
    }
    catch (Exception e)
    {
        HandleException(e); // Most likely will be a SocketException e.g. connection refused
        Connect(); // Try to connect again
    }
}

虽然我可以通过例如减少这种情况发生的可能性在放弃和退出递归之前添加最大重试次数,我宁愿这样写,以便释放内存并且不会发生堆栈溢出异常。

我想过把它放在一个 while 循环中,但我认为那会遇到同样的问题,例如

while (!connected)
{
    try
    {
        client = new TcpClient(ip, port);
        connected = true;
    }
    catch (Exception e)
    {
        HandleException(e);
    }
}

除了任意定义的最大重试次数之外,这里还有更好的方法来避免堆栈溢出异常吗?

我认为如果我们优雅地关闭套接字(通过添加 SocketException)那么无论递归方法调用 Connect() 多少次,我们都可以避免 Whosebug。此外,在我看来,如果由于任何给定原因连接失败,立即调用 Connect() 方法是没有意义的。我认为在再次调用之前稍作休息可以避免连续不断地面对类似的错误。

你可以试试这个:

async void Connect()
    {            
        Socket socket = null; //namespace System.Net.Sockets
        try
        {
            client = new TcpClient(ip, port);
            socket = client.Client; 
        }
        catch(SocketException se) //All socket related exceptions will be caught here
        {
            if (socket != null)
                socket.Close();
            //better to write exception in the log to fix the problem
            System.Threading.Thread.Sleep(1000 * 10); //Wait for few seconds before retrying
            Connect();
        }
        catch (Exception e)
        {
            HandleException(e); 
            //Connect(); // Try to connect again
        }
    }

正如 Lasse 在他的评论中所说:

一个。当涉及到内存和作用域时,循环与递归的行为不同,因此在这里使用递归更安全。

b。 运行 在技术上总是有可能进入堆栈溢出异常,但某些方法(如递归)通常比常规循环更容易出现这种情况。

我最终实现了一个带有一些额外条件的循环,例如最大重试次数。