TCP协议详解

1. 什么是TCP?

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

2. TCP的优点

面向连接:需要先建立连接才能进行通信

高可靠性:通过mss来判断最合适发送的数据块,避免数据分片。TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。

3. TCP的可靠性

MSS:TCP协议再三次握手的时候会协商每个报文段所能承载的最大数据长度,避免IP分片。

超时重传:当TCP发出一个报文段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能记时收到一个确认,它 就重发这个报文段。

确认响应:当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常延迟几分之一秒。

数据校验:TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化如果收到报文段的检验和有差错,TCP将丢弃这个报文段和不确认收到这个报文段。

数据排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能失序,因此TCP报文段的到达也可能失序。如果必要,TCP将对收到的数据进行排序,将收到的数据以正确的顺序交给应用层。

流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。

重复数据丢弃:IP数据报可能会出现重复,TCP的接收端必须丢弃重复的数据.

4. TCP的数据报文交互

4.1. TCP三次握手

 

(1)客户端发送第一个报文(SYN),报文的SYN标志为1。这个报文的作用是同步序号。客户端随机选择一个数字为第一个序号发送给服务端作为初始序号。(SYN报文时控制报文,不携带任何数据,会消耗一个序号)

 

(2)服务端收到后,发送第二个报文(SYN+ACK),其中SYN和ACK标志为1。作用是服务端使用这个报文来同步初始序号,然后通过ack标志确认收到客户端的SYN报文,同时期望客户端发送下一个序号。(SYN+ACK报文不携带任何数据,会消耗一个序号)

 

(3)客户端收到SYN+ACK后,发送ACK报文,ack标志为1,作用是确认收到服务端发送的报文。(ACK报文入宫不携带数据就不会消耗序号)

 

4.2. TCP三次挥手

 

(1)客户端发送FIN报文请求断开连接,fin标志为1。(FIN报文可以包含客户端发送的最后一块数据,也可以是一个控制报文)如果是控制报文则只消耗一个序号。

 

(2)服务端收到报文后,发送FIN+ACK确认收到客户端的FIN报文,同时告诉客户端自己正在关闭连接。ack标志为1,fin标志为1。(这个报文可以包含服务端的之后一块数据,如果不携带数据则只消耗一个序号)

 

(3)客户端收到报文后,发送ACK报文,确定收到了服务端的FIN+ACK报文。(不能携带数据,也不消耗序号)

 

4.3. TCP四次挥手

 

(1)客户端发送给FIN报文请求断开连接,fin标志为1。

 

(2)服务端收到后,发送ACK报文,告诉客户端数据还没有传完,需要继续发送数据。ack标志为1。

 

(3)服务端继续向客户端发送数据。

 

(4)服务端数据发送完后,向客户端发送FIN报文,fin标志为1。告诉客户端数据传完,关闭连接。

 

(5)客户端收到报文后,发送ACK报文,确认收到服务端的FIN报文。

 

 

 

5. TCP的报文格式及解析

 

源端口:发送端的端口号(16位)

目的端口:接收端的端口号(16位)

序号:用来标识从tcp发送端向接收端发送的数据字节,TCP是面向字节的,它会为每一个字节编一个号码,其中这里的序号是本报文段发送的数据的第一个字节的序号。(32位)

确认号:包含的值是该确认号的发送方期待接收的下一个序号,即最后成功接收的数据字节的序号加1。(32位)

头部长度:指出TCP头部字段一共有多少个4字节,头部长度可以在20~60字节之间,因此这个字段的值可以在5(5*4=20)到15(15*4=60)之间。(4位)

保留:保留今后使用。(6位)

URG:紧急,当该位为1的时候,表示紧急指针启用。说明该报文中有紧急数据,需要尽快传入上层应用,数据的第一位到紧急指针的位置就是紧急数据。(1位)

ACK:确认,当ACK为1的时候,确认序号才为有效的序号。否则确认序号无效。(1位)

PSH:推送,当PSH为1的时候,需要尽快将数据传入上层应用,而不用等整个缓存满了在上传。(1位)

RST:重置链接,当RST为1的时候,说明TCP连接出现问题,需要断开连接重新建立连接。(1位)

SYN:同步,当SYN为1的时候,用于初始化一个连接的同步序号。(1位)

FIN:结束,当FIN为1的时候,则是数据传完,请求断开连接。(1位)

窗口:定义发送TCP的窗口大小,以字节为单位。窗口大小由接受方定义。(16位)

检验和:对数据和报头进行校验。(16位)

紧急:只有URG为1时,这16为的字段才有效。该字段定义了紧急数据结束的地方。TCP创建报文时,把紧急数据插到报文的最前面。

选项:用于把附加信息传递给终点,或者用来填充对齐其他选项。我们将定义两大类选项:单字节赫尔多字节。

 

 

6. TCP重传

超时重传指的是,发送数据包在一定的时间周期内没有收到相应的ACK,等待一定的时间,超时之后就认为这个数据包丢失,就会重新发送。这个等待时间被称为RTO.

检测丢失报文的方法从概念上讲还是比较简单的,每一次开始发送一个TCP报文的时候,就启动重传定时器,定时器的时间一开始是一个预设的值(Linux 规定为1s),随着通讯的变化以及时间的推移,这个定时器的溢出值是不断的在变化的。如果在ACK收到之前,定时器到期,协议栈就会认为这个片段被丢失,重新传送数据。

 

TCP在实现重传机制的时候,需要保证能够在同一时刻有效的处理多个没有被确认的ACK,也保证在合适的时候对每一个片段进行重传,有这样几点原则:

 

1 . 这些被发送的片段放在一个窗口中,等待被确认,没有确认不会从窗口中移走,定时器在重传时间到期内,每个片段的位置不变,这个地方其实在滑动窗口的时候也有提到过

 

2 .只有等到ACK收到的时候,变成发送并ACK的片段,才会被从窗口中移走。

 

3 .如果定时器到期没有收到对应ACK, 就重传这个TCP报文。

 

重传之后也没有办法完全保证,数据段一定被收到,所以仍然会重置定时器,等待ACK,如果定时器到期还是没有收到ACK,继续重传,这个过程重传的TCP报文一直留着队列之内。

 

7. MTU和MSS的关系和计算

MTU:   Maximum Transmission Unit  最大传输单元

    首先看一下Ethernet帧的结构示意图:

 

       Ethernet帧的结构由6字节目标地址(48 bit)段、6字节的原地址段、2字节的type段、46-1500字节的数据段以及4字节帧尾CRC校验部分(FCS段)。这里说明一下前导符是是在物理层添加上去的,并不是正式帧的一部分。

      从上图可见,一个以太网帧最小64 Bytes(6+6+2+46+4) 最大1518 Bytes(6+6+2+1500+4),对于小于或者大于这个大小范围的以太网帧,一般的以太网转发设备都会丢弃这些数据帧。由于以太网Ethernet最大的数据帧长是1518 Bytes这样,刨去以太网帧的帧头(目标、源、类型共计14字节)14 Bytes和帧尾CRC校验部分FCS 4 Bytes,那么承载上层协议的Data域最大就只能有1500 Bytes。而这个值就是我们称之为MTU。

      MTU,即最大传输单元,这是一个数据链路层的概念,限定的是链路层数据帧长度。概念上是这样讲,但实际上MTU限制的并非数据链路层数据帧的长度,而是数据链路层的载荷部分(数据域)的长度。以上图所示Ethernet帧的结构可见,数据载荷部分的最大长度为1500 Bytes

MSS: Management Support System  最大报文长度

    最大报文段长度MSS选项是TCP协议定义的一个选项(是TCP协议里面的一个概念),MSS选项用于在TCP连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度(MSS是发送方与接收方通过TCP握手协商得出的)。

    MSS就是TCP数据包每次能够传输的最大数据分段。为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往用MTU值代替(需要减去IP数据包包头的大小20 Bytes和TCP数据段的包头20 Bytes)所以往往MSS为1460。通讯双方会根据双方提供的MSS值得最小值确定为这次连接的最大MSS值。

关系:

    MSS指的是TCP中的一个概念。MTU是一个没有固定到特定OSI层的概念,不受其他特定协议限制。也就是说第二层会有MTU,第三层会有MTU,像MPLS这样的第2.5层协议,也有自己的MTU值。并且不同层之间存在关联关系。

    举个例子:如果你要搬家,需要把东西打包,用车运走。这样的情况下,车的大小受路的宽度限制;箱子的大小受车限制;能够搬运的东西的大小受箱子的限制。这时可以将路的宽度理解成第二层的MTU,车的大小理解成第三层的MTU,箱子的大小理解成第四层的MTU,搬运的东西理解成MSS。

 

MTU与MSS的关系可以简单理解为:

MTU= MSS+TCP层头部长度+IP层头部长度 (MSS是指应用层在一个数据包内最大能传输的字节数,MTU是指IP层在一个数据包内最大能传输的字节数)

8. tcp报文的seq和ack代表的含义和计算

 

包1:

TCP会话的每一端的序列号都从0开始,同样的,确认号也从0开始,因为此时通话还未开始,没有通话的另一端需要确认(我使用的Wireshark版本和原作者不同,Wireshark1.10.2中,包1不显示确认号)

 

包2:

服务端响应客户端的请求,响应中附带序列号0(由于这是服务端在该次TCP会话中发送的第一个包,所以序列号为0)和相对确认号1(表明服务端收到了客户端发送的包1中的SYN)

需要注意的是,尽管客户端没有发送任何有效数据,确认号还是被加1,这是因为接收的包中包含SYN或FIN标志位(并不会对有效数据的计数产生影响,因为含有SYN或FIN标志位的包并不携带有效数据)

 

包3:

和包2中一样,客户端使用确认号1响应服务端的序列号0,同时响应中也包含了客户端自己的序列号(由于服务端发送的包中确认收到了客户端发送的SYN,故客户端的序列号由0变为1)

此时,通信的两端的序列号都为1,通信两端的序列号增1发生在所有TCP会话的建立过程中

 

包4:

这是流中第一个携带有效数据的包(确切的说,是客户端发送的HTTP请求),序列号依然为1,因为到上个包为止,还没有发送任何数据,确认号也保持1不变,因为客户端没有从服务端接收到任何数据

需要注意的是,包中有效数据的长度为725字节

 

包5:

当上层处理HTTP请求时,服务端发送该包来确认客户端在包4中发来的数据,需要注意的是,确认号的值增加了725(725是包4中有效数据长度),变为726,简单来说,服务端以此来告知客户端端,目前为止,我总共收到了726字节的数据,服务端的序列号保持为1不变

 

包6:

这个包标志着服务端返回HTTP响应的开始,序列号依然为1,因为服务端在该包之前返回的包中都不带有有效数据,该包带有1448字节的有效数据

 

包7:

由于上个数据包的发送,TCP客户端的序列号增长至726,从服务端接收了1448字节的数据,客户端的确认号由1增长至1449

 

在抓包文件的主体部分,我们可以看到上述过程的不断的重复,客户端的序列号一直是726,因为客户端除了最初的725字节数据没有再向服务端发送数据,服务端的序列号则与此相反,由于服务端不断的发送HTTP响应,故其序列号一直在增长

序列号为当前端成功发送的数据位数,确认号为当前端成功接收的数据位数,SYN标志位和FIN标志位也要占1位

 

关闭连接

 

包38:

在确认了服务端发送过来的最后一个数据段之后,客户端将处理整个HTTP响应并决定不需要进一步通信了。此时客户端发送设置了FIN标志位的包38,其确认号和之前的包37一样

 

包39:

服务端通过将确认号加1的方式回应客户端期望关闭连接的请求(这里和包2中确认SYN标志位时所作的操作是一样的),同时设置当前包的FIN标志位

 

包40:

客户端发送最终序列号727,通过将确认号加1的方式确认服务端的FIN包

 

此时,通信双方都终结了会话并且可以释放用于维持会话所占用的资源

posted @ 2018-05-09 14:26  阿鹏2019  阅读(475)  评论(0编辑  收藏  举报