【问题标题】:C# Always retry tcp connection if connection failedC# 如果连接失败,总是重试 tcp 连接
【发布时间】:2019-02-21 01:09:33
【问题描述】:

下面是我的代码,用于启动客户端到服务器的 tcp 连接:

Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);

连接回调:

    private void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            // Retrieve the socket from the state object.  
            Socket client = (Socket)ar.AsyncState;

            // Complete the connection.  
            client.EndConnect(ar);
        }
        catch (Exception ex)
        {
            _logger.Info(ex.ToString());
        }
    }

但我的代码只在我的系统启动时连接一次。如果第一次尝试失败,我们如何重试连接?

如果连接总是失败,总是会重试?

也许每 30 秒重试一次?

【问题讨论】:

  • 在失败的情况下从 ConnectCallback 启动另一个异步调用。如果要设置最大值,请传递失败的尝试次数。
  • 是否可以切换到 TPL(异步/等待任务)?
  • Fildor,我们如何检查连接是否失败?
  • "SocketException 尝试访问套接字时发生错误。" - MS Docs
  • 无论如何我都不会赶上Exception。你想抓住SocketException,因为那是你可以并且想要处理的。让其他人冒泡到您的全局异常处理程序。

标签: c# .net sockets tcp


【解决方案1】:
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);

如果您想跟踪失败的尝试并保持良好的异步模式,我会传递一个状态对象:

class ConnectionState {
    Socket Client {get; set;}
    int FailedAttempts {get; set;} = 0;
}

然后传递:

client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), new ConnectionState(){ .Client = client, FailedAttempts = 0});

在回调中:

private void ConnectCallback(IAsyncResult ar)
{
    ConnectionState state = (ConnectionState)ar.AsyncState;
    try
    {
        state.Client.EndConnect(ar);
    }
    catch (SocketException ex)
    {
        _logger.Info(ex.ToString());
        if( state.FailedAttempts < MAX_ATTEMPTS )
        {
            state.FailedAttempts += 1;
            state.Client.BeginConnect( remoteEP, new AsyncCallback(ConnectCallback), state );

            // you may also check the exception for what happened exactly.
            // There may be conditions where retrying does not make sense.
            // See SocketException.ErrorCode
        }
        else
        {
            // You may want to handle exceeding max tries.
            // - Notify User
            // - Maybe throw a custom exception
        }
    }
}

SocketException 错误代码参考:https://docs.microsoft.com/en-us/windows/desktop/winsock/windows-sockets-error-codes-2

为了设置基于时间的重试机制,我会创建某种“连接看门狗”:让计时器每 X 秒检查一次客户端字段。如果它为 null 并且连接启动尝试尚未运行,请启动一个。


不过,就我个人而言,我会尝试切换到TPL。但我认为这是一种替代方法,而不是您问题的直接答案。但我推荐它。

【讨论】:

  • 请问TPL是什么?
  • 如果我希望它永远重试怎么办?无需最大尝试次数
  • 我添加了指向答案的链接。但是,如果您不知道它是什么,阅读它可能需要相当长的时间。
  • “如果我希望它永远重试怎么办?” 然后只需 BeginConnect 而不检查,但是我会总是 让用户可以取消尝试。所以也许让它检查一些布尔值 ShouldRetryConnection (或类似的东西)。
  • 如果我想每 30 秒或 1 分钟重试一次怎么办?
猜你喜欢
  • 2010-09-28
  • 2020-12-15
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
  • 1970-01-01
相关资源
最近更新 更多