深入理解TCP的运输连接管理
我们都知道,TCP协议相对于UDP协议的一大优势,就是TCP协议提供可靠交付的服务。即通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。
我们都知道TCP协议是运输层的协议。该协议本身能够实现运输层的可靠通信,但是运输层之下的三层(特指目前最常用的ip协议等)是不能实现可靠通信的。也就是说,TCP协议是建立在不可靠的网络层之上的可靠传输协议。那么,我们如何保证它的可靠性呢?首先,我们必须建立连接。
TCP协议是面向连接的协议,也就是说,在传送数据之前,他必须先建立发送方和接受方之间的连接;在传完数据后,它必须切断双方的连接。我们把TCP传输过程中建立和断开连接的过程统称为TCP的运输连接管理。
现有的TCP协议通过三报文握手建立连接;通过四报文握手断开连接。为什么建立和断开连接分别需要三条和四条报文呢?如果采用更少的报文可以吗?我们通过举反例的方式来说明其是否可行。
1.TCP连接的建立
1)只采用一报文连接会怎样?
我们通过下图说明:
这是理想情况下的一报文握手连接。只要客户发出请求,就将自身状态变为ESTABLISHED(已连接);而服务器只要收到请求,也将自身状态变为ESTABLISHED。可以看到,在没有任何意外情况的条件下,一报文握手连接也是可以实现的。
但是,TCP是可靠的运输层协议,我们还必须考虑到各种各样的意外情况。只有在所有情况下都能传输成功,我们才能说这个协议是可靠的。
常见的意外情况有如下几种:
1.网络断开
2.网络延迟
3.丢包(网络没有断开的情况下)
我们来看一下如下的情况:
可以看到,客户发出请求后,将自身状态变为ESTABLISHED,而由于各种各样的原因,请求没有送达,服务器一直停留在LISTEN状态,这就是一种典型的错误情况。
图中写道错误情况为“真错”或“假错”,这个如何理解呢?
我是这样认为的:若客户与服务器有且仅有一方进入了连接状态,且无法通过重发请求解决这个错误的情况,就是“真错”;其他所有的情况都是“假错”。
在上图中,若丢包原因是因为网络断开,那么这个错误就无法用重发数据的方式解决,并且双方只有一方进入了连接态,造成资源浪费,所以就是真错;若网络没有断开,属于偶然丢包,那么就可以认为是假错,因为可以通过重发数据解决。TCP协议必须是可靠的,所以不能容许有任何真错的可能性,所以一报文连接无法完成稳定传输。
2)只采用二报文连接会怎样?
既然一报文连接无法保证稳定性,那我们就可以改为二报文连接,看看能否成功。
如下图是正常通讯的情况:
相比于一报文连接,二报文连接增加了一个SYN-SENT(同步信号送达)状态,在客户在收到服务器的回应后才开始ESTABLISHED状态。
上边是正常情况,那么异常情况呢?
我们看一下下图:
我们可以看到,我将这种错误标记为假错。这是为什么呢?
我们依然分两种情况讨论:
a)网络断开:在此情况下,客户请求无法送达,通过重发依然无法送达。但是,客户也没有进入连接状态(ESTABLISHED)。由之前我们的定义,它属于假错。因为只要客户没进入连接状态,那它就属于非连接态(尽管是SYN-SENT),那么客户就不会消耗太多资源。
b)偶然丢包:这个是用一报文就能排除的错误,只需重发数据就可解决,所以是假错,在此不再赘述。
再看如下情况:
这个情况是服务器的回应丢包了。因为客户的请求能够送达,所以网络是没问题的。那么丢包只能是偶然情况,所以可以通过重发解决。
下面看最后一种情况:
这是真错的情况。在教科书的解释中,这种情况叫做“已失效的连接请求报文段”。产生原因是网络发生了延迟,导致客户的请求过了好久才送达服务器。而客户早早就通过重发请求,传完了数据。这时第一次的请求才姗姗来迟。服务器在收到请求后,立马进入了ESTABLISHED状态。但这是无效信号,CLOSED状态的客户永远无法回应,所以服务器已知处在连接态,浪费资源。
由于客户已经传完了数据,没有再次重发数据的必要了,所以服务器永远也收不到下一步的指令了。这就需要进一步的改进。
3)采用三报文连接会怎样?
如上图所示,这时三报文握手的示意图。
下面看异常情况:
这个属于假错,原理同上,不再赘述。
失效连接造成的错误:
这个和二报文连接的错误三原因一样,都是“已失效的连接请求报文”,但是,由于采用了三次握手,服务器必须等到客户的再次请求才能进入连接态。事实是客户处于关闭状态,不会回应请求。这样服务器就是处于SYN-RCVD状态,不会进入连接态而造成资源浪费。
2.总结
通过上边的论述,我们知道采用一报文和连接和二报文连接都无法百分之百保证稳定传输,所以只能采用三报文传输。(四报文断开连接的情况下次再写)