拿捏网络之TCP协议

        解释TCP之前,我们先了解一个概念:TCP/IP协议,这个协议总是被一些人搞混,TCP/IP协议并不是一个协议,而是一组协议的统称。起这个名字是因为TCP与IP是整体架构的核心协议。网络的四层架构就是TCP/IP的分层模型。

什么是TCP?

        传输控制协议(Transmission Control Protocol,缩写为TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

TCP的特点?

        基于流的方式:TCP可以一个字节一个字节的接收数据,而不是一个规定格式的数据块。

        可靠传输:即使因为网络原因导致数据乱序接收,也会在客户端进行重新排序,保证数据正确性。

        流量控制:TCP使用滑动窗口功能,确保传输的数据不会超出接收方接收数据的能力。

面向连接:TCP只关注连接双方,不考虑中间网络跳转。

TCP的报文格式

        源端口 (Source Port):16位的源端口表示报文的发送端口。源端口和源IP组成报文的返回地址。

        目的端口 (Destination Port):16位的目的端口表示报文的接收端口。目的端口和目的IP组成报文的接收地址。

        序号 (Sequence Number):是本TCP报文所发送数据的第一个字节的序号。TCP协议中数据部分每个字节都有他的序号。

        确认号 (Acknowledgment Number):是期望收到对方发送的下次报文数据部分第一个字节的序号。

        头部长度/数据偏移 (Header Length/Data Offset):该字段表示头部包含多少个32位数据,4位的最大值是15,所以TCP报文头部最大为60个字节。

        预留字段 (Reserved):全部置为0,预留字段,暂无意义。

        标志位 (Flags):表示TCP包的特定连接状态。占用6位,每一位对应一个状态。

                URG:URGent表示紧急,当一个报文被标记为紧急报文,该报文需要尽快发送,而不是按原来的次序来发送。

                ACK:表示报文已成功被接收。TCP协议规定建立连接后,所有的报文ACK字段都为1

                PSH:表示通知接收端处理接收的报文,而不是将报文放在buffer缓存中。

                RST:重连标志,用于重置由于主机崩溃或者其他原因而出现的错误连接,可以拒绝一个无效的数据请求。

                SYN:同步标志,TCP建立连接的第一步,会将SYN置为1.

                FIN:表示发送端已将数据发送完毕。

        窗口大小 (Window):表示发送端期望一次接收的数据量。

        校验和 (Checksum):TCP头部和数据部分进行校验和计算,接收端用于对收到的数据包进行验证。

        紧急指针(Urgent Pointer):表示报文中第一个紧急数据字节的指针。只有当URG标志位为1时,才有效。

        选项和填充 (Options And Padding):表示TCP可选选项和位数对齐填充,使TCP头部为32位的整数倍。

TCP建立连接过程

        TCP建立连接的过程需要经过三次请求的交互,俗称三次握手。我们先来看一下三次握手的过程。

        第一次握手:Client进入SYN_SEND状态,发送一个SYN报文(SYN标志位为1),并指明Client的初始序列号ISN,即seq = x。

        第二次握手:Server收到Client的SYN报文,反手发送一个SYN确认报文(SYN标志位和ACK标志位为1),并指明自己的初始序列号ISN,即seq = y。同时将Client的ISN+1,作为确认序号ack的值,表示Server已经收到了Client发送来的SYN报文,并希望收到的下一个报文数据的第一个字节的序号是x+1,Server进入SYN-RCVD状态。

        第三次握手:Client收到Server的SYN确认报文,会发送一个确认收到报文。把Server的ISN+1作为ack的值,表示已收到Server发送的SYN确认报文,希望收到的下一个数据的第一个字节的序号是y+1,Client进入Established状态。Server收到Client的确认收到报文后,也进入Established状态。双方开始发送数据。

过程图示

TCP断开连接过程

        断开连接过程涉及两个角色:主动断开连接方,下文用A代替;被动断开连接方,下文用B来代替。

        第一次挥手:A向B发送一个断开连接请求的报文(FIN标志位为1),指明A的ISN,即seq=a。A进入FIN_WAIT_1状态,表示A已经没有数据要发给B了,准备关闭socket连接。

        第二次挥手:在收到A发送的断连报文后,B会发送一个断连确认报文(ACK标志位为1),指明自己的ISN,即seq=b,将Client的ISN+1,作为确认序号ack的值,表示B已经收到了A发送的断连报文,并希望收到的下一个报文数据的第一个字节的序号是a+1。进入CLOSE_WAIT状态,B通知应用程序关闭连接,直到应用程序反馈关闭成功,CLOSE_WAIT状态依然可以传输数据。A收到B的断连确认报文后进入FIN_WAIT_2状态。

        第三次挥手:B收到应用程序关闭连接成功的反馈后,向A发送可以断开连接的报文(FIN标志位与ACK标志位为1),指明B的ISN,即seq=c,ack还是a+1。A进入LAST_ACK状态。

        第四次挥手:A收到B发送可以断开连接的报文,向B发送确认关闭连接报文(ACK标志位为1),指明B的ISN,即seq=a+1。A转入TIME_WAIT状态,等待2MSL的时间后,转入CLOSED状态。B收到确认报文后转入CLOSED状态,完成整个断开连接的过程。

过程图示

关于TCP的面试题

        TCP建立连接为什么需要三次握手?

                我们设想这样一个场景,在外的游子自从上了大学回家的次数便越来越少,小小的电话便是我们唯一的沟通方式,但是由于电话信号是不可靠的,我们总需要先确定对方是否能听到的话。

                        我:喂?妈!能听到吗?

                        妈妈:能听到?你那边能听到吗?

                        我:我能听到。

                三次握手的过程就是这个互相试探的过程。

                        第一次握手,Client询问Server是否可以接收消息,希望得到Server的回应。

                        第二次握手,Server收到了Client的询问,Server再把去试探Client能否正常接收信息。

                        第三次握手,Client收到了Server的状态,Server可以给Client发消息了。

        这里包含了双方的互相试探。

        如果改成2次握手,则Server不会知道Client是否能接收确认信息。比如这样

                 建立连接是失败的,但Server还是会发送数据。

                而四次握手是完全没有必要的,因为3次就已经满足需求了。

        TCP断开连接为什么需要四次挥手?

                这个其实很好理解,在上学的时候,老师就像主动断开连接的一方。

                        老师:我们这堂课要讲的东西已经讲完了,剩下的时间你们自习吧,有问题的同学上来问。

                        学生们:好的,老师

                        这段时间,学生可以提问题~~~

                        学生们:老师,我们没有问题了

                        老师:好,下课

                四次握手的原因就是,我要讲的讲完了,你还有要说的,你就说,说完咱再下课。反映在图中。

        TIME_WAIT为什么需要等待2MSL?

                MSL(Maximum Segment Lifetime) 报文最大生存时间,MSL的时间是从被动方接收到FIN后发送ACK开始计时。如果主动方没有接收到ACK报文,被动方收到FIN报文的超时重传,MSL将会重新计时。

                需要等待2MSL,相当于至少允许断连确认报文丢失一次。增强稳定性。


版权声明:本文为qq_22156459原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。