跳转至主要内容

一个常见的误解是,TCP保证数据的交付。TCP实际保证的是,它将把数据传送到接收主机的TCP堆栈中,或者向发送应用程序报告一个错误。不幸的是,错误报告并没有说明实际交付了多少数据。接收TCP栈和接收应用程序之间也有很大的区别。

有两种基本的故障情况。在第一种情况下,发送的TCP堆栈没有收到它正在传输的数据的TCP确认。在这种情况下,发送应用程序可以继续调用send将更多的数据放入TCP栈的发送缓冲区。一旦TCP栈超时传输,发送应用程序调用的下一次发送(或接收)就会显示ETIMEDOUT错误。应用程序现在知道出现了问题,但不知道成功传输了多少数据。成功意味着发送的TCP栈收到了接收的TCP栈对数据的确认。

在第二种情况下,发送的TCP协议栈传输数据并收到一个复位而不是确认。复位可能表明接收的TCP协议栈已经关闭了套接字,或者一些网络设备(可能是防火墙)已经超时。下次发送应用程序调用send(或receive)时,就会显示ECONNRESET错误。你可能会认为在这种情况下,发送应用程序可以推断出只是上次发送调用的数据失败了,但你就错了。有可能是发送的TCP协议栈将多个发送调用的数据缓冲到一个TCP段中,而这个段触发了复位,或者是在复位之前发送了一系列的TCP段,由系列中的第一个段触发,回到了发送方。发送应用程序所能推断的是,并不是所有的数据都被成功传输了。

还有第三种故障情况,与TCP(发送或接收)栈或网络无关。假设接收应用程序有一个bug使其无法读取数据。接收TCP栈将继续接收数据并发送TCP确认,直到TCP接收缓冲区填满为止。然而,这可能是高达64K字节的数据(或更多,如果支持TCP窗口缩放)。如果接收应用程序需要重新启动,TCP接收缓冲区中的所有数据都将丢失。当接收应用程序被终止时,接收TCP堆栈应该(但可能不会)向发送TCP堆栈发送一个复位。它将在下一次收到现在已关闭的连接的段时发送复位。从发送应用程序的角度来看,这与第二种情况类似。然而,它指出,即使接收的TCP栈确认了数据,在发生错误的情况下,发送方认为接收应用程序已经读取了数据是不安全的。

从这些故障场景中可以看出,如果没有应用层的确认,传输超时或重置错误表明,部分,可能是所有传输的数据可能没有被接收应用程序读取。出于这个原因,我建议所有的应用程序都包含应用层确认,准备好重新建立连接和重新传输未确认的数据,并能够处理重复的数据,因为可能丢失的是确认。

© 2024Stratus Technologies.