我正在编写一个服务,它需要维护到远程服务器的长期运行的SSL连接。我需要这台服务器能够自我修复,也就是说,如果它因任何原因断开连接,那么下一次写到它时,它将重新连接。我试过这个:
bool isConnected = client.Connected && client.Client.Poll(0, SelectMode.SelectWrite) && stream.CanWrite;
if (!isConnected )
{
this.connected = false;
GetConnection();
}
stream.Write(bytes, 0, bytes.Length);
stream.Flush();但我发现它不像我所期望的那样。如果我通过禁用wifi来模拟网络中断,我仍然能够用stream.Write()写入流大约20秒。然后,下次我尝试写它时,client.Connected、client.Client.Poll()或stream.CanWrite()都不会返回false,但是当我写到流时,我会得到一个套接字异常。最后,如果我尝试重新创建连接,就会得到这个异常:一个现有的连接被远程主机强制关闭。
我希望任何帮助创建一个长期运行的SslStream,可以抵御网络故障。谢谢!
发布于 2014-08-30 05:36:40
SSL的底层协议是TCP。TCP通常只在应用程序希望发送数据时发送数据,或者需要通过发送ACK来回复从另一方接收的数据。这意味着,在尝试发送任何数据之前,将不会注意到断开的连接(如丢失的链接)。但你不会立即注意到,因为:
EPIPE一样。这意味着,如果您想要预先知道连接是否仍然有效,您必须确保在连接上进行定期的数据交换。在TCP级别上,您可以设置TCP_KEEPALIVE,但这可能会在交换数据包之间使用几个小时的间隔。在SSL层,您可能尝试使用臭名昭著的心跳扩展,但大多数对等方都不会理解它。最后一种选择是在自己的应用程序中实现某种心跳。
至于自愈:当重新连接时,您将得到一个新的TCP连接,并且您还需要进行一个完整的SSL握手,因为最后一个SSL连接没有完全关闭,因此无法恢复。服务器不知道这个新连接只是旧连接的延续,因此您必须在客户端和服务器上实现跨应用程序层内多个TCP连接的某种元连接。在这个元连接中,您需要有自己的数据跟踪来检测哪些数据真正从对等端被接受,哪些数据只被发送,但由于连接中断而从未被显式接受。听起来像是TCP上的TCP。
发布于 2014-08-29 21:21:36
从10.000英尺的角度看:
关闭wifi后仍然可以写入流的原因是,有一个网络缓冲区保存数据以进行传输。reach的成功意味着网络接口(TCP/IP堆栈)已接受该数据并已被缓冲以进行传输,而不是数据已到达其目标。
TCP/IP堆栈需要时间才能注意到完全的媒体断开(连接丢失/重置),因为即使没有物理链接,TCP/IP也会将其视为网络中的一个临时问题,并将持续重试一段时间(网络可能在某个时候丢弃数据包,堆栈将继续重试)。
如果您以相反的方式考虑这一点,您不会希望所有的程序都失败,如果有网络问题(这种情况在互联网上经常发生),因此TCP/IP会花时间通知应用程序层连接已失效(经过多次重试并等待了合理的时间)。
当SslStream失败并继续发送数据时,您可以始终重新连接到服务器,尽管您会发现这并不容易,因为有几种情况下,您发送的数据和服务器没有接收到数据,而服务器完全没有从服务器接收任何ACK .因此,根据你的需要,光靠自我治疗是不够的。
自愈实现简单,数据一致性和可靠性更难,通常要求服务器准备支持某种可靠的消息传递机制,以确保所有数据都已发送和接收。
https://stackoverflow.com/questions/25574515
复制相似问题