PS:限于本人目前能力有限,只能将自己理解的一些简单的原理加以说明,难免存在很多缺陷或不足,望大家批评指正,同时,我会不断的完善这篇文章,因为明白这些底层的原理对以后的提高和调优的原理、系统的设计都具有一定的指导意义
TCP协议是面向连接的、可靠的字节流服务。很多应用层协议,诸如FTP、HTTP都是基于TCP来完成的,下面从几个方面来记录下自己对TCP协议的一些理解。
- TCP的基本概念
- TCP的基本原理
- 参考资料
一、TCP的基本概念
传输层协议最多听说的就是TCP与UDP。而大家也同样知道TCP协议提供了面向连接的、可靠的字节流服务,那么TCP是如何实现可靠的呢?有如下几点:
- 应用数据被分割成TCP认为最合适发送的数据块。这些数据块也被称为segment,相应的问题:Q1:TCP如何确定报文段的长度呢?
- 当TCP发出一个segment后,启动一个timer(定时器),等待目的端确认接收到这个segment。如果不能及时收到一个确认,将重发该segment,相应问题:Q2:TCP的超时及重传机制?
- 当TCP收到来自连接另一端的数据,它将发送一个确认。这个确认不是立即发送的,通常会推迟,相应问题:Q3:为何应答会推迟?
- TCP将保持它首部和数据的校验和
- TCP的segment作为IP数据报来传输(IP,网际层协议),而IP数据报的到达可能会失序,因此TCP的segment也可能失序。如果有必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层,相应问题:Q4:如何实现对segment的排序?
- TCP接收端会丢弃重复报文
- TCP提供流量控制,即TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。
以上,的若干理由,就是TCP为什么能提供可靠的、面向连接的、字节流服务的原因,下面将对上述的问题进行解答,也就是TCP实现这些机制的基本原理。
二、TCP的基本原理与问答
Q1:TCP是面向连接的,那么TCP是如何建立连接的?又是如何断开连接的?
A1:TCP的建立是通过3次握手实现的,而连接的断开是通过4次握手,也就是说发生了7次segment的传递,这里有几个重要的名词:
SYN(Synchronize Sequence Numbers):同步序列号
ACK(Acknowledgement Number):确认标志
FIN:结束标志
以上字段均出现在TCP Header中,下面看下TCP的报文头
下面来描述下,TCP连接的建立过程:
1.客户端,发送一个SYN i同步请求,并包含一个初始序列号(ISN:initial Sequence Number)
2.服务端,接收到客户端segment,并对此segement进行应答,在ACK = i + 1;同时应答的segment,有自己的SYN k;
3.客户端,接收到服务端segment,并对此segment进行应答,ACK = k + 1。
4.服务端,接收到客户端的ack segment,连接建立。
注:在这里,主动发起连接的一方称为主动打开(active-open);被动接收的一方称为被动打开(LISTEN)
下面描述下,TCP连接的关闭过程:
1.客户端,发起主动关闭请求, FIN M
2.服务端,对客户端的segment进行应答,ack = M + 1
3.服务端,服务端向客户端也发送一个结束通知 FIN N
4.客户端,接收到服务端的通知,对服务端进行应答, ACK = N + 1
5.服务端,关闭
以上则是TCP的连接建立与关闭过程
Q2:TCP如何确定报文长度?
A2:TCP Header中的可选字段中,包括一个最长报文大小(Maximum Segement Size,MSS)字段,它指明本端所能接收的最大长度的报文段(segment),并在每次通信的第一个segment中指明该选项;其中MSS的默认值为536byte,也就是说当数据被封装入IP数据报后,为IP Header + TCP Header + Data = 576;
当然,TCP协议有自己的更合理的切割数据段的方式,由于水平有限,目前解释不了其机制。
Q3:TCP的超时及重传机制?
A3:TCP的重传机制,是其可靠性的保证之一。因为TCP是面向连接的,也就是point to point的形式,那么当某一端发送数据后,会启动一个定时器,并规定一个时间阀值,当对端的响应超时、接到ICMP的segment丢失的报文时,将会触发重传该数据报。
那么,这里有一个问题就是时间阀值的确定,其中有一个参考量为RTT(往返时间测量),TCP计算该RTT的平局值与方差,进而设置一个重传的时间。
实际中的处理场景会更复杂,本次也不提及。
Q4:为何会应答推迟?
A4:理解为何有应答推迟,需要考虑一件事,Tcp每次发送的都有什么:正规的segment以及小的交互数据(应答);那么如果每个小的交互数据,都直接发送,在广域网中有可能会造成拥塞,使效率降低;这样就有了一种考虑,将这种小的segment,组成一个大的segment再发送出去,采用的算法就是Nagle。Nagle的定义为:在一个tcp连接中,只允许有一个未被确认的未完成的小分组。
这就是为什么会出现应答推迟的原因。
注:应答推辞在某些场景是不需要的,例如,在远程连接的控制中(如QQ的远程协助),控制着需对自己的操作由一个实时的反馈,如鼠标的移动。
Q5:如何实现segment的排序?
A5:产生segment无序的原因是网际层的IP协议导致的,因为IP协议的宗旨是:以最短的路径将IP数据报送往目的地址,这样,很有可能导致经由IP数据报封装的TCP segment到达目的地不一致。
这时的解决办法就是,在传输层通过TCP对segment进行重组,所依赖的东西就是:窗口大小+ Seq + 确认Seq。通常,通过窗口大小,判断要接收的数据块有几个:假设客户端发送了seq为:1,2,3,4,5,这5个segment;而因为线路的原因,服务端只接收到了seq为5的segment,那么服务端会ack seq为5的segment的,并向客户端要其他的segment,这样,客户端根据判断会进行重发或其他操作。
Q6:TCP中窗口大小?
A6:接收方与发送方的窗口大小,即应用的缓冲区大小,默认大小为4096,并且缓冲区大小会影响传输的质量,同时该缓存大小可以根据,媒体带宽与两端返回值进行计算。下面根据图解释下窗口的概念:
描述下上图的过程(图片来自《TCP/IP详解:卷一》),在连接建立的两次应答中,分别是client与server确认对方的缓冲区大小,client端说,自己的缓冲区4096,最大报文段是1460;server端说,自己的缓冲区是4096,最大报文段是1024。
接下来,客户端发送了4个segment,每次1024;server的应答为已经接收,win 0,即缓冲区已满,因为读取缓冲区是应用层的事情(应用程序负责读取),TCP无法控制,同时因为缓冲区已满,所以client端也不再发送;过一段后,server发送ack,表示数据已经接收,缓冲区(窗口大小)4096,可以继续发送,client端又继续发送,server接着应答;最后确认此次数据传输接收,以上就是TCP中的窗口。
也就是说,发送方,试图去填充接收方的窗口(缓冲区)
三、参考资料
《TCP/IP详解:卷一》
wiki百科:传输控制协议