TCP协议
转自车小胖专栏
TCP报文可以说是最常见的报文之一,但TCP具体的工作原理了解的人却不多,在这里展开来说一说这个TCP协议,了解比较深或者想要完整了解这个协议的朋友可以直接去查阅 RFC793
,本文只是尽量写一些TCP比较重要的功能及实现,远远达不到全面、准确这两点。
简介
TCP = TRANSMISSION CONTROL PROTOCOL,即传输控制协议。
在网络中,TCP协议处于第四层,在物理层(线缆,光纤,无线信道等),数据链路层(交换层面segment),网络层(IP)这三个层面之上的一层协议。也就是说,在我们讨论TCP协议的时候,意味着我们的前提是IP可达,ping包可通的情况下。
那为什么要设计TCP协议呢?因为实际需求就在那里,好吧我来翻译这句话。
首先我们知道,需要给两台设备设计的通信有很多很多,比方说你要上传/下载文件,发送QQ消息,发送邮件等等,如果把这些协议都设计成三层,那么IP协议将会十分复杂且低效。所以我们新增了四层端口号这个概念,将网络拓展到了四层。这时候两种声音出现了,一种声音是可靠传输,但会损失一些性能;另一种声音是不需要可靠传输,要的是更低的延迟,更精简的包头。因为有这两种不同的需求,所以TCP和UDP两种协议便被设计并规范出来。可以说TCP是为了满足多样,可靠的传输而出现的产物。
包头
当我们谈及网络协议时,最简单的方法就是看它的包头,如果能深刻的理解包头每个字节的作用,那么你也就真正的理解了这种网络协议。不多说,上图。
前文已经说过,TCP协议设计出来的主要目的是为了满足多样、可靠这两种需求。图中的前三行,4个字段,共12个字节很好的解释了这一点。
Source Port & Destination Port: 16 bits*2
源端口和目的端口各占16 bits,也就是说我们可以拥有2^16 = 65536个端口号,也就是说我们可以开放这6万多个端口给一台设备提供不同的服务。
Sequence Number & Acknowledgment Number: 32 bits*2
这两个字段各自占据了TCP包头4个字节的位置,其重要性可想而知,而且TCP的可靠传输主要是靠这两个字节来实现,具体它们是如何实现在工作这一小节去具体描述。再往下看。
Data Offset: 4 bits
因为TCP包头中有部分可选字段,所以我们需要一个指针来指示数据的开始的地方,Data Offset字段完成的就是这顶功能。有细心的同学会发现,它的最大值为2^4 = 16,而图中的TCP包头已经有24个字节了,这里要特殊说明的是,这里的1是代表1行,也就是4个字节的内容,我们可以表示的范围是(0 ~ 15)*4 = 0 ~ 60字节,而TCP最少占有20个字节,这就意味着我们最多有40个字节的可选字段可以使用。
Reserved: 6 bits
这是保留字段,不用时设为0。或许当我们需要实现新的功能时,这6个bit可以提供相应的标识。目前后三个bit已经有用作标识, NS 、 CWR 、 ECE ,有兴趣的同学可以自己去看看相关RFC的规定。
Control Bits: 6 bits
URG: Urgent Pointer field significant
确认是否有紧急指针,即第五行后面的Urgent Pointer字段。
ACK: Acknowledgment field significant
确认是否为ACK信息,除了初始的SYN包外,这个字段都应标为1。
PSH: Push Function
确认是否将数据推给上层协议,如果是1则推送,如果是0则先缓存下来。
RST: Reset the connection
确认是否重置连接,如果出现重大差错,会将该字段置为1。
SYN: Synchronize sequence numbers
确认是否为同步序列号,只有从端发出的第一个包才会将该该置为1.
FIN: No more data from sender
确认是否中断。如果发送方将信息发送完毕则将该字段置为1。
Window: 16 bits
表示从确认号开始,本报文的源方可以接收的字节数,即源方接收窗口大小。这是个很有意思的机制,有机会再展开讨论一下。
Checksum: 16 bits
对整个的TCP报文段,包括TCP头部和TCP数据,以16位字进行计算所得。该字段主要确认在信道传输过程中,内容无差错。
Urgent Pointer: 16 bits
用作指针,指到紧急数据的结束位。主要用途是传输一些紧急数据,这里不展开说了。
Options & Padding
扩展字段,前文已经计算过,最长为40个字节,这里也不展开说了。
Data
数据,前面那么多包头的信息,传输的就是这数据,研究协议的时候,我们把他看作成一个整体就好,不用关心我们到底利用这个协议传输了什么内容。至于MTU长度,分片等内容也很重要,有时间再写吧。
工作原理
因为不能把所有的IP协议都当作TCP协议来使用,所以我们规定,当检测到IP协议中PROTOCOL字段为6时,我们将IP字段后的协议视为TCP协议。也就是说,我们讨论的前提又加了一项,TCP协议被调用。
TCP的功能有很多很多,在这里选择介绍两项关注比较多的内容,连接建立/断开和流量控制。如果一起讨论其它功能,可以在评论区留言说明。
连接建立/断开
一个正常的TCP连接从建立到分开,要完成三次握手四次挥手。先是建立,见图。
- 客户端向服务器申请建立TCP连接,向服务器端发送一个SYN报文,作为第一次握手。客户端把这段连接的SYN设定为随机数A。
- 服务器端收到SYN报文后,会给客户端发送一个报文。报文中ACK的确认码为A+1,同时发送另一个SYN为随机序号B。
- 此时,客户端收到ACK为A+1的报文,将之与发送的SYN包进行比对,如果满足+1的关系,则在客户端判断连接已建立。并给服务器发送确认数据包,SYN为A+1,表明已收到上一报文,ACK为B+1,通知服务器进入连接状态。
至此,TCP连接建立完毕,可以正常传输数据了。再是连接终结,即四次挥手,还是看图。终结连接操作可由双方任意一方发起。本文以客户端发起为例。
- 客户端向服务器端发送一个FIN报文,作为第一次挥手。通知服务器,我已经没有数据还要发送。但不确认服务器是否扔有数据返回,所以连接仍是建立状态。
- 服务器收到FIN报文,返回一个ACK报文,告诉客户端,我知道你已经没有东西要发送了,但我还要再确认一下我是不是还有东西要给你。
- 服务器判断自己也没有报文需要发送给客户端,发送FIN消息,告诉客户端,好了,这下我也没有东西要给你了,你可以终结连接了。此时服务器不确认客户端是否收到信息,继续保持连接。
- 客户机收到ACK和FIN消息后,得知服务器已经知道自己要终结,并且无更新内容,便给服务器发送一个ACK说我知道了,你也终结吧,客户机便终结连接。服务器在收到最后一条ACK后,也终结连接。
至此,四次挥手操作完成,连接终结。
拥塞控制
要注意的是,拥塞控制和流量控制不是一回事,今天要说的是拥塞控制,流量控制有机会再聊。拥塞控制是TCP协议设计中一个很棒的特性,这个特性让TCP协议在网络传输中合理的利用带宽,使速度最大化。TCP中的拥塞控制用到以下几种技术,慢启动、拥塞避免、快速重传和快速恢复技术。
慢启动技术。如果连接建立好,一上来就给对端发大量的报文,可能无法到达,并造成网络链路的拥塞。慢启动技术是开始会发很小的报文给对端,收到对端的ACK判断可达后,会加倍报文量发送同时等待,如果收到对端的ACK则继续加倍,如果等待超时且没有收到ACK则意味着报文过大,超过链路负荷,开始发送原有报文+1大小的报文,如此反复。以达到最大利用带宽。
可以说,慢启动是拥塞控制技术的核心。但如果在传输中遇到了链路不稳定,TCP则会让传输速度降至谷底,将窗口设为1,继续慢启动。这样,一个小小的干扰就让速度损失这么多,并且浪费了带宽,IT人肯定是不同意的,所以就有了后面几种机制。这么多的技术,其目的只有一个,尽可能大的利用带宽!抓住这一点再对后面的技术产生和原理进行理解,将事半功倍。这里就不再展开继续说明了。
总之,这次写了不少东西,也挖了不少坑,具体要不要填,填哪些坑,希望和朋友们一起探讨,欢迎大家留言。
最后,贴一下TCP完整的逻辑判断及状态机流程图,如果能看懂这张图以及上面的报文图。可以说你已经对TCP有了一个较深的理解了。