【问题标题】:Lost data on dropped TCP connectionTCP 连接断开时丢失数据
【发布时间】:2013-03-19 21:43:20
【问题描述】:

场景是我通过家庭网络上的 TCP 将数据从一台机器传输到另一台机器。发送者实例化一个TCPClient,并将数据写入GetStream()返回的NetworkStream。我的理解是,NetworkStream 中的数据最终会被发送到 NIC 上的缓冲区并通过物理介质传输。

但是,如果连接中断,MemoryStream 中的数据和 NICs 缓冲区中的数据会丢失,但是在我的应用程序中,数据被写入流中,我可以天真地假设数据被发送到监听套接字,但显然不是这样。一旦重新建立连接,应用程序将继续发送数据,据其所知,传输被中断,但这没有考虑到 NIC 缓冲区和MemoryStream 对象中丢失的数据。

除了编写我自己的应用层协议之外,还有什么办法可以解决这个问题吗?

【问题讨论】:

    标签: c# tcpclient


    【解决方案1】:

    假设写入到套接字的数据可以保证到达。这意味着 TCP 堆栈必须在每个数据包之后等待确认。

    显然,这不是它的工作原理。

    除非您成功关闭连接,否则 TCP 不保证到达。只有这样你才知道一切都已收到。

    您可能需要在应用层建立恢复协议。询问对方你在第一次连接中走了多远。

    cmets 中的大量讨论使我得到以下澄清:如果连接中断,发送方无法可靠地知道对方接收了多少字节。他将可靠地知道不是所有的东西都收到了,但不是什么收到了。

    【讨论】:

    • 嗯,如果我正在编写应用程序级协议,我还不如只使用 UDP。很好的答案和很好的见解——谢谢。
    • 这个答案是错误的——“除非你成功关闭连接,否则 TCP 不保证到达。只有这样你才知道一切都收到了。”,这没有任何意义。就 TCP 而言,关闭连接不会改变任何事情。如果数据被刷了,会重试,直到对方成功确认。 TCP 确实可以保证数据包的到达,但对这些数据包的处理/操作取决于应用程序。
    • "如果数据被刷了,会重试,直到对方成功确认。"这不是真的。如果链接永久关闭怎么办?然后应用程序认为数据已经到达,而实际上还没有。告诉我如何确保数据确实到达,或者在流中未接收到数据的位置出现可靠错误。你不会找到答案。即使 Flush 确实保证了交付,但在所有其他没有调用 flush 的地方都无法保证交付。如果你写 1000 个字节,900 个可能会到达,100 个可能不会。你会怎么看?
    • 真的。应用程序永远不会认为收到了一个尚未收到的数据包,流将失败并引发异常。你的第一句话说的是错误的,它确实在每个数据包后等待确认,如果没有得到它,它会重试。这不是一个同步过程,其他数据包可以乱序发送,它们只是不会被乱序接收(由链路层再次处理,它会在传递之前重新排序数据堆栈)。
    • 如果写入1000字节,则会收到1000字节,否则会抛出异常
    【解决方案2】:

    有几个选项。一种方法可能是在每批数据写入后手动将数据刷新到NetworkStream 上的管道中。

    虽然这可能被视为性能问题,但根据您的应用程序类型,这将是最容错的方法。通过手动调用.Flush(),您将知道数据是否成功发送到管道。

    如果您从您的MemoryStream 批量执行此操作到NetworkStream,您可以存储“最后写入的字节”,并能够将它们放回您的MemoryStream,准备重新重新建立连接时尝试。

    另一种选择是实现您自己的协议,在连接时,立即向客户端发送服务器迄今为止收到的字节数(即自上次连接以来)。当你有了这些信息,你就可以清除你的MemoryStream的前X个字节(已经发送的那些),然后继续下推剩下的数据。

    您可以做的最后一件事,可能是最好的方法,就是将两者结合起来。基本上实现一个发送/确认协议。这意味着,您将发送一大块数据,并等待服务器发回 ACK/OK。当它收到时,您可以确定服务器已收到此数据,但如果没有,您可以继续重试,直到收到该 ACK。

    【讨论】:

    • Flush 不保证发货,因为它不等待确认。
    • TCP 协议“保证交付”的本质,因为它会不断重试发送数据包。如果在调用链接层上的 Flush 之后没有发送该错误,则该错误将冒泡到应用程序。
    • 它不保证交付(面对失败的网络怎么可能?!)。该应用程序将在任意时间收到通知,而不是在另一方仍收到数据的时间点。如果您不同意,请说明如何实施。
    猜你喜欢
    • 1970-01-01
    • 2017-09-08
    • 2021-02-28
    • 1970-01-01
    • 2021-07-16
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多