TCP协议内部知识介绍

Posted 巴山雨夜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP协议内部知识介绍相关的知识,希望对你有一定的参考价值。

今天我们主要介绍一下TCP协议,关于TCP协议大家听到的都比较多了,我也就不需要详细介绍了,大家向下看就是了。

1、TCP基本知识

TCP提供了一种面向连接的、可靠的字节流服务。面向连接比较好理解,就是连接双方在通信前需要预先建立一条连接,这犹如实际生活中的打电话。助于可靠性,TCP协议中涉及了诸多规则来保障通信链路的可靠性,总结起来,主要有以下几点:
(1)应用数据分割成TCP认为最适合发送的数据块。这部分是通过“MSS”(最大数据包长度)选项来控制的,通常这种机制也被称为一种协商机制,MSS规定了TCP传往另一端的最大数据块的长度。值得注意的是,MSS只能出现在SYN报文段中,若一方不接收来自另一方的MSS值,则MSS就定为536字节。一般来讲,在不出现分段的情况下,MSS值还是越大越好,这样可以提高网络的利用率。
(2)重传机制。设置定时器,等待确认包。
(3)对首部和数据进行校验。
(4)TCP对收到的数据进行排序,然后交给应用层。
(5)TCP的接收端丢弃重复的数据。
(6)TCP还提供流量控制。(通过每一端声明的窗口大小来提供的)

2、调研TCP定时器的使用

在TCP协议中有的时候需要定期或者按照某个算法对某个事件进行触发,那么这个时候,TCP协议是使用定时器进行实现的。在TCP中,会有四种定时器:

  • 重传定时器
  • 坚持定时器
  • 保活定时器
  • 2MSL定时器
这四个定时器都有各自的具体作用。

重传定时器

TCP是可靠的,因此,它对于发出去的信息,没有得到正常ACK反馈的,都会启动一个重传机制。这个重传机制使用一个重传定时器,当发现在规定时间内,没有收到ACK,那么,重新发送消息,如果还没有收到ACK,继续重新发送消息...当然,这每次继续重新发送消息的时间间隔是不一样的。一般默认,第一次重传是发现超时后1s,第二次重传是第一次重传后3s,第三次是6s...

说回术语,重传定时器最重要的计算数值叫RTO(Retransmission Timeout, 重传超时时间)。这个重传超时时间又是根据RTT(Round Trip Time, 连接往返时间)计算出来的。然后呢,这个RTT不是固定设置的,是计算机根据不同的网络情况和机器情况测量出来的。在RFC中,对RTT,RTO的算法有详细的说明。

坚持定时器

坚持定时器是使用在一方滑动窗口为0之后,另外一方停止传输数据,进入坚持定时器的轮询,直到滑动窗口不再为0了。

说说术语,首先是滑动窗口,可以简单理解为缓冲区剩余空间大小。不管是写缓冲还是读缓冲,一旦一方通告了自己的滑动窗口大小,另外一方就会根据滑动窗口大小传递窗口大小的数据了。但是,当被通告,一方的滑动窗口大小为0的时候,另外一方就会启动坚持定时器,基本也是使用TCP指数退避方法,第一次1.5秒,第二次1.5x2秒,第三次1.5x4...

其次是糊涂窗口综合症。这个症状是滑动窗口引起的。病因是发送方和接收方在一个很小的滑动窗口的时候就开始数据传输,传输结束之后,读写的消费速度也并没有那么快,导致下次传输的时候,滑动窗口还是那么小。然后现象就是每次传输的数据都非常小。就好比每次开出去的火车载货量只有一节车厢,其实我们是希望能攒够n节车厢才开始传输。

糊涂窗口综合症有解决办法,还不止一种,在接收方或者发送方都可以解决。大致就是如果接收方解决,那么接收方在接收窗口小于一定大小的时候,对所有的接收请求都返回窗口为0的包,来触发另外一方的坚持定时器。同样发送方也是,在可以发送的数据大于一定窗口的时候才发送。

保活定时器

这个就是我们经常说的tcp的keepalive了。实际使用场景是在应用层没有数据进行传输的时候,一定时间(tcp_keepalive_time,默认每2个小时)发送一次保持心跳的包,如果发送成功,则继续保持端口活跃,如果没有正常返回,则在指定次数内(tcp_keepalive_probes,默认是9次),指定间隔(tcp_keepalive_intvl,默认是17s)发送心跳包。如果最后都没有获得正常的ACK,那么才算连接失败。

当然,tcp是否需要提供keepalive机制,是有争议的,我们可以为每个tcp连接设置是否启用keepalive和启用keepalive的各个指标设置。参考大话keepalive

2MSL定时器

这个定时器用在TCP四次挥手之后,主动发起TCP断开的一方需要保持2MSL的TIME_WAIT的状态。这个保持的一方就会开启2MSL定时器来计算TIME_WAIT的状态保持时间。

3、TCP报文格式

TCP的报文格式一般如下


报文首部地址内容介绍:

源端口号和目的端口号:分别占用16位,表示源端口号和目的端口号;用于区别主机中的不同进程, 而IP地址是用来区分不同的主机的,源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一 的确定一个TCP连接;
32位的序列号:用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据 字节在数据流中的序号;主要用来解决网络报乱序的问题;
32位确认序列号:包含发送确认的一端所期望收到的下一个序号,因此,确认序号应 当是上次已成功收到数据字节序号加1。表示的是ACK之前的数据报文我已经受到了。不过,只有当标志位中的ACK标志(下面介绍)为1时该确认序列号的字 段才有效。主要用来解决不丢包的问题;
4位首部长度:表示此报文中首部的长度,基本单位一般是4个字节.这个字段占4位(最多能 表示15个4字节的的字,即4*15=60个字节的首部长度),因此TCP最多有60字节的首部。然而,没有任选字段, 正常的长度是20字节;

保留的六位:被用作是未来的使用的。
6位标志位:TCP首部中有6个标志比特,它们中的多个可同时被设置为1,主要是用于操控TCP的状态机的,依次 为URG,ACK,PSH,RST,SYN,FIN。每个标志位的意思如下:
URG:此标志表示TCP包的紧急指针域有效,用来保证TCP连接不被中断,并且督促 中间层设备要尽快处理这些数据;
ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1, 为1的时候表示应答域有效,反之为0;
PSH:这个标志位表示Push操作。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序, 而不是在缓冲区中排队;
RST:这个标志表示连接复位请求。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包;

SYN:表示同步序号,用来建立连接。SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1, ACK=0;连接被响应的时候,SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送 一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这 种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全 的主机将会强制要求一个连接严格的进行TCP的三次握手;
FIN: 表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志 位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。

16位的窗口大小:也就是有名的滑动窗口,用来进行流量控制;一般表示的是本方的窗口的大小。

16位的校验和:用来检测首部校验。

通过上面的介绍我们,大致知道了这些TCP报文的地址格式,相信大家都对此有了一定的了解,但是下面我们还有这么的一个问题要说:

4、URG、PUSH两者的使用场景,并且两者之间有什么区别?

紧急URG(URGent):

当URG = 1时表明紧急指针字段有效,他告诉系统此报文段中有紧急数据,应尽快传送,而不要按原来的排队顺序来传送,发送方的TCP就把紧急数据放到本报文段数据的最前面。URG标志位要与首部中的紧急指针字段配合使用,紧急指针指向数据段中的某个字节,(数据从第一个字节到指针所指的字节就是紧急数据)。值得注意的是即使窗口为0时也可以发送紧急数据,紧急数据不进入接收缓冲区直接交给上层进程。

推送PSH(push):

当两个应用进程进行交互式通信时,有时客户发一个请求给服务器时希望立即能够收到对方的响应,这种情况下,客户应用程序通知TCP使用推送(push)操作,TCP就把PSH置为1,并立即创建一个报文段发送过去,类似的服务器的TCP收到一个设了PSH标志的报文段时就尽快将所有收到的数据立即提交给服务进程,而不在等到整个缓存都填满了再向上交付。

URG和PSH的区别:

URG:紧急标志位,表示的是此报文段中有紧急数据,将紧急数据排在普通数据的前面;当接受端收到此报文后后必须先处理紧急数据,而后再处理普通数据。 
PSH: 催促标志位,当发送端将PSH置为1时,TCP会立即创建一个报文并发送。接受端收到PSH为1的报文后就立即将接受缓冲区内数据向上交付给应用程序,而不是等待缓冲区满后再交付。

5、TCP“三次握手,四次挥手”

我们都知道TCP通信是面向连接的,每次通信都需要经过三次握手与四次挥手来建立与释放连接。 下面的一幅图是合理的介绍了TCP的三次握手与四次挥手的过程: 参考链接

【三次握手】

在TCP/IP协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号 并交换 TCP窗口大小信息。 【1】.第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Seq为x;然后,客户端进入SYN_SENT状态,等待服务器的确认;
【2】.第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Ack为x+1(Seq+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Seq为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RCVD状态;
【3】.第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Ack设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
完成了三次握手,客户端和服务器端就可以开始传送数据。以上就是TCP三次握手的总体介绍。

其中的几个状态分别代表:

LISTEN - 侦听来自远方TCP端口的连接请求; 

SYN-SENT -在发送连接请求后等待匹配的连接请求; 

SYN-RCVD - 在收到和发送一个连接请求后等待对连接请求的确认; 

ESTABLISHED- 代表一个打开的连接,数据可以传送给用户;

CLOSED - 没有任何连接状态;

【四次挥手】

当客户端和服务器通过三次握手建立了TCP连接以后,当数据传送完毕,肯定是要断开TCP连接的啊。那对于TCP的断开连接,这里就有了神秘的“四次分手”。
【1】.第一次分手:客户端A,设置Seq和Ack,向服务端B发送一个FIN=1报文段;此时,客户端A进入FIN_WAIT_1状态;这表示客户端A没有数据要发送给服务器B了;
【2】.第二次分手:服务器B收到了客户端A发送的FIN报文段,向客户端A回一个ACK报文段,Ack为Seq加1;客户端A进入FIN_WAIT_2状态;服务器B告诉客户端A,我也没有数据要发送了,可以进行关闭连接了; 【3】.第三次分手:服务器B向客户端A发送FIN报文段,请求关闭连接,同时服务器B进入CLOSE_WAIT状态;
【4】.第四次分手:客户端A收到服务器B发送的FIN报文段,向服务器B发送ACK报文段,然后进入TIME_WAIT状态;服务器B收到客户端A的ACK报文段以后,就关闭连接;此时,客户端A等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,客户端A也可以关闭连接了。
至此,TCP的四次分手就这么愉快的完成了。

为什么TCP连接需要三次握手,为什么不是两次握手、四次握手?

TCP的这样设计都是有原因的: 假设Tcp进行的两次握手的话:当客户端向服务器请求连接的时候,client给server发送了SYN请求连接报文,server收到SYN报文之后,确定建立连接的话,并且给client回上一个ACK确认报文,自此执行好了两次握手,但是server给client发送的ACK报文在传输的 过程中可能丢失,此时server认为连接建立,但是client没有收到ACK确认,认为连接没有建立。此时继续连接的时候server认为连接已经建立并,就不会再次建立连接。导致了server中的错误连接会占用的越来越多,产生问题。 假设Tcp要进行的是四次握手的话:三次就已经可以解决了,四次就浪费了。

以上是关于TCP协议内部知识介绍的主要内容,如果未能解决你的问题,请参考以下文章

【网络协议笔记】第四层:传输层(Transport)TCP协议简介(1)

(chap2 TCP/IP基础知识) TCP/IP分层模型的通信流程

HTTP协议知识体系核心重点梳理

计网传输层(TCPUDP可靠传输流量控制......)

计网传输层(TCPUDP可靠传输流量控制......)

计网传输层(TCPUDP可靠传输流量控制......)