我有一个以下方法连接到程序启动时的终点
ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); var remoteIpAddress = IPAddress.Parse(ChannelIp); ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort); ChannelSocket.Connect(ChannelEndPoint);
我还有一个定时器,设置为每60秒触发一次CheckConnectivity
,它会尝试将任意字节数组发送到终点,以确保连接仍然存在,如果发送失败,它将尝试重新连接.
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)); } }
所以我如何测试上面的内容,就是从我的以太网设备上拔掉LAN电缆,允许我的代码尝试重新连接(显然会失败)并重新连接回LAN电缆.
但是,即使重新连接LAN电缆(能够ping)后,我的重新连接方法中的ChannelSocket.Connect(ChannelEndPoint)也会抛出此错误
No connection could be made because the target machine actively refused it 192.168.168.160:4001
如果我要重新启动整个应用程序,它会成功连接.我如何调整我的重新连接方法,以便我不必重新启动我的应用程序以重新连接回我的以太网设备?
如果应用程序关闭TCP/IP端口,则协议规定端口保持TIME_WAIT
状态一段时间(在Windows计算机上默认为240秒).请参阅以下参考 -
http://en.wikipedia.org/wiki/Transmission_Control_Protocol
http://support.microsoft.com/kb/137984
http://www.pctools.com/guides/registry/detail/878/
这对您的场景意味着什么 - 是您不能期望在短时间内(甚至几秒钟)关闭(自愿或不情愿)并重新打开端口.尽管您在互联网上找到了一些注册表调整..该端口将无法在Windows上的任何应用程序中使用,至少30秒.(再次,默认为240秒)
你的选择 - 这里有限......
来自http://msdn.microsoft.com/en-us/library/4xzx2d41(v=vs.110).aspx上的文档-
" 如果套接字先前已断开连接,则无法使用this(Connect
)方法恢复连接.请使用其中一种异步BeginConnect
方法重新连接.这是底层提供程序的限制. "
文档建议BeginConnect
必须使用的原因是我上面提到的..它根本不希望能够立即建立连接..因此唯一的选择是异步调用,而你等待在几分钟内建立的连接,确实期望并计划失败.基本上,可能不是一个理想的选择.
如果漫长的等待和不确定性是不可接受的,那么您的另一个选择是以某种方式协商客户端和服务器之间的不同端口.(例如,理论上,您可以使用无连接的 UDP 来协商您重新建立连接的新TCP端口).当然,理论上使用UDP的通信本身并不能保证设计.但是大部分时间都应该工作(今天,典型组织中的网络并不是那么片状/不可靠).主观的情景/意见,或许比选项1更好,但更多的工作和更小但有限的机会不工作.
正如其中一条评论中所建议的那样,这就是http和http服务等应用层协议具有优势的地方.如果可以的话,使用它们而不是低级插座. 如果可以接受,这是最好的选择.
(PS - 仅供参考 - 对于HTTP,操作系统内置了很多特殊处理,包括windows - 例如,有一个专门的驱动程序Http.sys
,专门用于处理试图在同一端口80上侦听的多个应用程序等.这里的详细信息是另一个时间的主题..重点是,有很多善良和辛勤工作为你做,当涉及到HTTP
)