TCP连接丢失数据
本文关键字:数据 连接 TCP | 更新日期: 2023-09-27 18:04:28
这个场景是我在家庭网络上通过TCP将数据从一台机器传输到另一台机器。发送方实例化一个TCPClient
,并将数据写入GetStream()
返回的NetworkStream
。我的理解是NetworkStream
中的数据最终被发送到NIC上的缓冲区并通过物理介质传输。
然而,如果连接中断,MemoryStream
中的数据和nic缓冲区中的数据将丢失,但在我的应用程序中,数据被写入流,我可以天真地假设数据被发送到侦听套接字,但显然不是这样。一旦连接重新建立,应用程序将继续发送数据,据其所知,传输被中断,但这并不考虑在NIC的缓冲区和MemoryStream
对象中丢失的数据。
有没有办法解决这个问题,除了写我自己的应用层协议?
假设写入套接字的数据可以保证到达。这意味着TCP栈必须在每个数据包之后等待确认。
显然,它不是这样工作的。
TCP不保证到达,除非你已经成功关闭连接。只有这样你才知道一切都收到了。
你可能需要在应用层建立一个resume协议。问对方你在第一次连接中走了多远。
评论中的许多讨论使我得出以下澄清:如果连接中断,发送方不能可靠地知道另一方收到了多少字节。他将可靠地知道并不是所有的都收到了,而不是收到了的内容。
有几个选项。一种方法可能是在每批数据写入后手动将数据刷新到NetworkStream
上的管道中。
虽然这可能被视为性能症结,但这取决于您的应用程序类型,这将是最容错的方法。通过手动调用.Flush()
,您将知道数据是否成功地发送到管道中。
如果你从MemoryStream
批量到NetworkStream
这样做,你可以存储"最后写的字节",并能够把它们放回你的MemoryStream
,准备在连接重新建立时重新尝试。
另一种选择是实现你自己的协议,在连接时,立即向客户端发送服务器到目前为止接收到的字节数。自上次连接以来)。有了这些信息后,可以清除MemoryStream
的前X个字节(已经发送的),并继续下压其余的数据。
你可以做的最后一件事,可能是最好的方法,是两者的结合。基本上实现一个发送/确认协议。这意味着,您将发送一个数据块,并等待服务器发回ACK/OK。当它返回时,您可以确定服务器已接收到此数据,但如果没有,则可以继续重试,直到获得该ACK。