Переполнение стека в TcpClient (рекурсия) - PullRequest
0 голосов
/ 30 апреля 2020

Из-за повторных вызовов 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
    }
}

Хотя я могу уменьшить вероятность этого например, добавив максимальное количество попыток перед тем, как отказаться от рекурсии и выйти из нее, я бы лучше записал ее, чтобы освободить память и исключений переполнения стека не возникало. l oop, но я думаю, что возникнет та же проблема, например,

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

Есть ли лучший способ избежать исключений переполнения стека, кроме как иметь произвольно заданное максимальное количество повторений?

Ответы [ 2 ]

0 голосов
/ 04 мая 2020

Как сказал Лассе в своих комментариях:

a. У l oop не то же самое поведение, что и у рекурсии, когда дело доходит до памяти и области видимости, поэтому здесь это безопаснее.

b. Технически всегда возможно столкнуться с исключениями переполнения стека, но некоторые подходы, такие как рекурсия, обычно более склонны к этому, чем обычные циклы.

В конечном итоге я реализовал все oop с некоторыми дополнительными условиями, например, для максимального количества повторов .

0 голосов
/ 01 мая 2020

Я думаю, что если мы аккуратно закроем сокет (добавив SocketException), тогда мы сможем избежать Stackoverflow независимо от того, сколько раз рекурсивный вызов метода Connect (). Кроме того, по моему мнению, не имеет смысла вызывать метод 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
        }
    }
...