2

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

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

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

4

2 回答 2

2

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

显然,这不是它的工作方式。

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

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

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

于 2013-03-18T19:19:16.890 回答
0

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

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

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

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

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

于 2013-03-18T19:26:11.703 回答