如何重新连接到插座优雅 [英] How to reconnect to a socket gracefully

查看:146
本文介绍了如何重新连接到插座优雅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个连接到终点下面的方法我的程序启动时

I have a following method that connects to an end point when my program starts

ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var remoteIpAddress = IPAddress.Parse(ChannelIp);
ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort);
ChannelSocket.Connect(ChannelEndPoint);

我也有一个设置为触发每隔60秒调用 CheckConnectivity ,尝试发送一个任意字节数组到终点,以确保一个计时器,该连接还活着,如果发送失败,它会尝试重新连接。

I also have a timer that is set to trigger every 60 seconds to call CheckConnectivity, that attempts to send an arbitrary byte array to the end point to make sure that the connection is still alive, and if the send fails, it will attempt to reconnect.

public bool CheckConnectivity(bool isReconnect)
{
    if (ChannelSocket != null)
    {
        var blockingState = ChannelSocket.Blocking;
        try
        {
            var tmp = new byte[] { 0 };
            ChannelSocket.Blocking = false;
            ChannelSocket.Send(tmp);
        }
        catch (SocketException e)
        {
            try
            {
                ReconnectChannel();
            }
            catch (Exception ex)
            {
                return false;
            }
        }
    }
    else
    {
        ConnectivityLog.Warn(string.Format("{0}:{1} is null!", ChannelIp, ChannelPort));
        return false;
    }

    return true;
} 

private void ReconnectChannel()
{
    try
    {
        ChannelSocket.Shutdown(SocketShutdown.Both);
        ChannelSocket.Disconnect(true);
        ChannelSocket.Close();
    }
    catch (Exception ex)
    {
        ConnectivityLog.Error(ex);
    }

    ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    var remoteIpAddress = IPAddress.Parse(ChannelIp);
    ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort);
    ChannelSocket.Connect(ChannelEndPoint);
    Thread.Sleep(1000);

    if (ChannelSocket.Connected)
    {
        ConnectivityLog.Info(string.Format("{0}:{1} is reconnected!", ChannelIp, ChannelPort));
    }
    else
    {
        ConnectivityLog.Warn(string.Format("{0}:{1} failed to reconnect!", ChannelIp, ChannelPort));
    }
}

所以,我怎么想测试上面的,是身体从我的以太网设备拔掉网络线,让我的code尝试重新连接(这显然失败),并重新连接背面的LAN电缆。

So how I'd test the above, is to physically unplug the LAN cable from my ethernet device, allowing my code to attempt to reconnect (which fails obviously) and reconnect back the LAN cable.

然而,即使重新连接LAN电缆(能ping通)后,ChannelSocket.Connect(ChannelEndPoint)在我重新连接方法总是抛出这个错误

However, even after reconnecting the LAN cable (able to ping), ChannelSocket.Connect(ChannelEndPoint) in my Reconnect method always throws this error

No connection could be made because the target machine actively refused it 192.168.168.160:4001

如果我要重新启动我的整个应用程序,连接成功。我该如何调整我重新连接方式,使得我没有重新启动我的应用程序,以重新回到我的以太网设备?

If I were to restart my whole application, it connects successfully. How can I tweak my reconnect method such that I don't have to restart my application to reconnect back to my Ethernet device?

推荐答案

如果应用程序关闭TCP / IP端口,协议规定该端口停留在 TIME_WAIT 状态在一段时间内(在Windows计算机上默认的240秒)。 见下为参考 -

If an application closes a TCP/IP port, the protocol dictates that the port stays in TIME_WAIT state for a certain duration (default of 240 seconds on a windows machine). See following for references -

<一个href="http://en.wikipedia.org/wiki/Transmission_Control_Protocol">http://en.wikipedia.org/wiki/Transmission_Control_Protocol

http://support.microsoft.com/kb/137984

<一个href="http://www.pctools.com/guides/registry/detail/878/">http://www.pctools.com/guides/registry/detail/878/

这意味着您的方案 - 的是,你不能指望关闭(自愿或非自愿),并重新打开端口的时间(甚至是几秒钟)在短期内。尽管某些注册表调整,你会发现在互联网上..端口将取消适用于在Windows任何应用程序,为至少30秒。 (同样,默认 240秒)

What this means for your scenario - is that you cannot expect to close (willingly or unwillingly) and re-open a port within a short period of time (even several seconds). Despite some registry tweaks which you'd find on internet.. the port will be un-available for any app on windows, for a minimum of 30 seconds. (Again, default is 240 seconds)

您的选项 - 在这里是有限的......

Your options - here are limited...

  1. 从文件的<一个href="http://msdn.microsoft.com/en-us/library/4xzx2d41(v=vs.110).aspx">http://msdn.microsoft.com/en-us/library/4xzx2d41(v=vs.110).aspx -
  1. From the documentation at http://msdn.microsoft.com/en-us/library/4xzx2d41(v=vs.110).aspx -

如果套接字已经previously断开连接,那么你就不能使用这个(连接)的方法来恢复连接,使用异步之一 BeginConnect 的方法来重新连接。这是潜在的供应商的限制。

"If the socket has been previously disconnected, then you cannot use this (Connect) method to restore the connection. Use one of the asynchronous BeginConnect methods to reconnect. This is a limitation of the underlying provider."

为什么文件表明 BeginConnect 必须使用的原因,就是我上面提到的。它根本不指望能建立连接的时候了..因此唯一的选择就是使异步调用,而你的连接迫不及待地想成立于几分钟,确实期望和计划,因而失败。 从本质上讲,这可能不是一个理想的选择。

The reason why documentation suggests that BeginConnect must be used is what I mentioned above.. It simply doesn't expect to be able to establish the connection right away.. and hence the only option is to make the call asynchronously, and while you wait for the connection to get established in several minutes, do expect and plan for it to fail. Essentially, likely not an ideal option.

如果在漫长的等待和不确定性是不能接受的,那么你的另一种选择是,以某种方式协商客户端和服务器之间不同的端口。 (例如,在理论上可以使用UDP,这是连接,洽谈新的TCP端口,你会重新建立的连接)。使用UDP通讯,在课程理论,本身没有被设计保证。但是,应该大部分的时间(今天,网络在典型的组织是不是片状/不可靠的)。 主观场景/意见,也许比选择1更好,但更多的工作和不工作的小,但有限的机会。

  1. If the long wait and uncertainty is not acceptable, then your other option is to somehow negotiate a different port between the client and server. (For example, in theory you could use UDP, which is connectionless, to negotiate the new TCP port you'd re-establish the connection on). Communication using UDP, in theory of course, itself is not guaranteed by design. But should work most of the times (Today, networking in typical org is not that flaky / unreliable). Subjective to scenario / opinion, perhaps better than option 1, but more work and smaller but finite chance of not working.

作为建议的意见之一,这就是像HTTP和HTTP服务的应用层协议有优势。使用,而不是低水平的插座他们,如果你能。 如果可以接受的,这是去与最好的选择。

As suggested in one of the comments, this is where application layer protocols like http and http services have an advantage. Use them, instead of low level sockets, if you can. If acceptable, this is the best option to go with.

(PS - 仅供参考 - 对于HTTP,还有很多特殊的处理内置到操作系统,包括Windows - 例如,有专门的司机则Http.sys ,专为处理多个应用程序试图在同一端口80等对听..这里的细节是另一次的话题..关键是,有大量的善良和勤奋为你做,当谈到<$ C $的C> HTTP )

(PS - FYI - For HTTP, there is a lot of special handling built into OS, including windows - For example, there is a dedicated driver Http.sys, specially for dealing with multiple apps trying to listen on same port 80 etc.. The details here are a topic for another time.. point is, there is lots of goodness and hard work done for you, when it comes to HTTP)

这篇关于如何重新连接到插座优雅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆