【问题标题】:Self-healing SslStream自愈 SslStream
【发布时间】:2014-08-30 13:43:51
【问题描述】:

我正在编写一个服务,该服务需要与远程服务器保持长期运行的 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,我将不胜感激。谢谢!

【问题讨论】:

  • 你必须使用 SslStream,你能使用像 WCF 这样的更高层抽象,它内置了这些健壮性功能吗?
  • 我不拥有等式的服务器端,所以我不能更改为 SSL 以外的任何东西。
  • 当连接被切断时,你不知道收到了什么,没有收到什么。重启会比你想象的更难。 TCP 不保留消息边界。

标签: c# .net networking


【解决方案1】:

从 10.000 英尺的角度来看:

关闭wifi后仍然可以写入流的原因是因为有一个网络缓冲区正在保存要传输的数据,stream.Write/stream.Flush成功意味着网络接口(TCP / IP堆栈)已接受数据并已缓冲传输,而不是数据已到达其目标。

TCP/IP 堆栈需要一段时间才能注意到完全的媒体断开连接(连接丢失/重置),因为即使没有物理链接,TCP/IP 也会将此视为网络中的临时问题,并将继续重试一段时间(网络可能会在某个时候丢弃数据包,堆栈将继续重试)

如果您以相反的方式考虑这一点,您不会希望所有程序在出现网络故障时都失败(这种情况在互联网上经常发生),因此 TCP/IP 会花时间通知应用程序连接失效的层(重试几次并等待一段合理的时间)

当 SslStream 失败时,您始终可以重新连接到服务器并继续发送数据,尽管您会发现并非如此简单,因为有几种情况您发送而服务器没有接收到数据,而其他情况下服务器接收到了数据,而您根本没有收到来自服务器的任何 ACK...所以根据您的需要,仅靠自我修复可能是不够的。

自我修复实现起来很简单,数据一致性和可靠性更难,通常需要服务器准备好支持某种可靠的消息传递机制,以确保所有数据都已发送和接收。

【讨论】:

    【解决方案2】:

    SSL 的底层协议是 TCP。 TCP 通常只会在应用程序希望它传递数据,或者如果它需要通过发送 ACK 来回复从另一端接收到的数据时发送数据。这意味着,在您尝试发送任何数据之前,不会注意到诸如丢失链接之类的断开连接。但你不会立即注意到,因为:

    • 对套接字的写入只会将数据传送到 OS 内核,如果传送成功则返回成功。
    • 然后内核将尝试将数据传递给对等方并等待来自客户端的 ACK。
    • 如果它没有收到任何 ACK,它将再次重试以传递数据,并且只有在重试失败后,内核才会宣布连接断开。
    • 只有在连接被内核标记为断开后,下一次写入或读取才会将错误从内核返回到用户空间,就像在执行写入时返回 EPIPE

    这意味着,如果您想预先知道连接是否仍然存在,您必须确保在连接上获得定期数据交换。在 TCP 级别,您可以设置 TCP_KEEPALIVE,但这可能会在交换数据包之间使用几个小时的间隔。在 SSL 层,您可能会尝试使用臭名昭著的心跳扩展,但大多数同行不会理解它。最后的选择是在您自己的应用程序中实现某种心跳。

    关于自我修复:重新连接时,您会获得一个新的 TCP 连接,并且您还需要进行一次完整的 SSL 握手,因为最后一个 SSL 连接没有完全关闭,因此无法恢复。服务器不知道这个新连接只是旧连接的延续,因此您必须在客户端和服务器的应用程序层内实现某种跨越多个 TCP 连接的元连接。在这个元连接中,您需要有自己的数据跟踪来检测,哪些数据是真正从对等方接受的,哪些数据只是发送但由于连接中断而从未明确接受。听起来像是 TCP 之上的一种 TCP。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-31
      • 2012-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-09
      • 1970-01-01
      相关资源
      最近更新 更多