TCP原理与应用详解

1. TCP首部介绍


TCP原理与应用详解

首先介绍首部字段:

源端口和目的端口: 提供复用和分用,应用层的进程都可以通过传输层再传输到IP层,这就是复用,分用就是传输层从IP层收到数据后必须交付给指明的应用层应用进程。

序号: TCP为传送的字节流每一个字节进行按照顺序编号,序号是本报文段的第一个字节编号,序号和确认号主要是为了数据的可靠性进行的多方面的考虑。

确认号: 确认号就是期望收到对方的下一个报文段的第一个数据字节的序号。当确认号位N,则表示N-1之前的数据都已经收到了。

首部长度: 说明TCP报文段的首部长度,取值范围5-15,按照四字节对齐,所以首部长度范围也就是20字节-60字节。

保留位: 目前全为0,提供给以后使用

URG: URG为1的时候,此时紧急指针是有效的,此时会告诉操作系统此报文段有紧急数据,应当尽快传送,紧急数据说的就是数据从第一个字节到紧急指针的内容。不进入接收缓冲,就直接交给上层进程,其他数据都是要进入接收缓冲的。URG不进入缓冲。

ACK: ACK是用来确认的,当ACK为1的时候,确认字段有效,ACK为0,确认字段无效。

PSH: PSH是在两个应用的进程在进行通信的时候,当一方的进程希望输入命令以后立即就能够收到对方的响应,此时就使用PUSH。PSH=1,此时就立即创建一个报文发送出去,接收方收到这个报文段以后,直接交付给应用进程,不在等到整个缓存都填满了再向上交付。交付依然在缓冲区。

RST: RST叫做重置位,当RST为1,此时说明连接中出现重大差错,此时必须释放连接,然后重新建立连接。

SYN: 用来同步序号,连接建立时,SYN=1,表示一个连接请求或链接接受报文。

FIN: 用来释放一个连接,FIN=1的时候,此时表示此报文段发送方数据全部发送完,释放连接。

窗口大小: 窗口大小,指的是发送本报文段的一方的接收窗口,窗口值作为接收方让发送方设置其发送窗口的依据,窗口值告诉对方,从本报文段首部中的确认号算起,接收方允许对方发送的的数据量。窗口字段明确指出了现在允许对方发送的数据量,窗口值是经常在动态变化着。

检验和: 用于检验TCP首部和TCP数据,同UDP一样检验的时候也需要加上伪首部进行检验。

紧急指针: 指出紧急数据范围,进行紧急操作,搭配URG,把紧急数据放入传送队列最前面传送出去

选项: 长度不固定,可以改变,最长可达40字节,选项SACK选择确认的时候可以使用,使用多个指针标注不连接序号的段落

注意: 一般来说TCP是要等到整个缓存都填满了后再向上交付,但是如果PSH=1的话,就不用等到整个缓存都填满,直接交付,但是这里的交付仍然是从缓冲区中交付的,URG是不要经过缓冲区的,千万记住!

2. TCP的特点


  1. TCP面向连接

  2. TCP面向字节流

  3. TCP保证可靠传输

  4. TCP支持全双工通信

  5. TCP支持端口到端口的连接,每一条TCP连接只能有两个端点

3. TCP三个重要问题


TCP中的三个重要的问题:可靠传输,流量控制和拥塞避免。

3.1可靠传输

可靠传输:

确认和重传:接收方收到报文就会确认,发送方发送一段时间后没有收到确认就重传。

数据校验。

数据合理分片和排序:tcp会按MTU合理分片,接收方会缓存未按序到达的数据,重新排序后再交给应用层。

3.2流量控制

如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。

TCP利用可变窗口大小进行流量控制。

3.3拥塞避免

在某段时间,若对网络中的某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变化,这种情况叫做拥塞。TCP为了解决拥塞问题,使用了算法,有慢启动和拥塞避免,还有快重传和快恢复。

后续会有博客更新对这三个问题再来探究。

4. TCP连接管理


首先我们需要了解下相关的TCP的连接相关,连接需要什么呢?

其实就是解决三个问题:

- 使得双方互相感知到彼此的存在

- 允许双方协商一些参数(例如滑动窗口大小,为了更好的进行流量控制等其他内容)

- 能够对运输实体资源进行分配(缓存大小等内容)

TCP建立连接的方式是客户服务器方式,其实也就是两个应用进程建立连接,一个客户机应用进程,一个服务器引用进程。

所以TCP的连接,其实也就是三个过程,分别是连接建立,数据传输和连接释放。我们把连接建立叫做TCP的三次握手。连接释放叫做TCP的四次挥手。接下来我们就深入来看一下这两个过程。

4.1 TCP的连接建立(三次握手)

TCP连接的建立,首先看下面的示意图:

TCP原理与应用详解

首先我们需要知道TCP是客户机向服务器的请求,客户机是主动的打开连接,服务器是被动的打开连接。

B的服务器进程首先创建传输控制块TCB,准备接受客户进程的连接请求。然后服务器进程就处于LISTEN(收听)状态,扽带客户机的连接请求。接受到请求,做出响应。

A客户机也是首先创建传输控制块TCB,然后向B发送连接请求报文段,报文首部同步位SYN=1,同时选择一个序号seq=x。SYN报文段不能携带数据,但是要消耗掉一个序号,接下来,TCP客户机进程进入SYN-SENT(同步已发送)状态。

当B收到连接请求报文段后,如果同意建立连接,则向A发送确认,在这个确认报文段,需要把SYN同步位和ACK确认位都设置为1,同时确认序号ack=x+1,同时为自己选择一个初始序号seq=y,当然确认报文段也不能携带数据,但是需要消耗掉一个序号,这个时候服务器进程进入SYN-RCVD(同步收到)状态。

客户机ATCP进程收到服务器B的确认以后,还需要给B给出确认,确认报文段ACK确认位为1,确认序号ack=y+1,而自己序号seq=x+1。ACK报文段可以携带数据。但是如果不携带数据则不消耗序号,接下来,TCP连接通过三次握手已经建立,客户机A进入ESTABLISHED(已建立连接)状态。

服务器B接收到A确认的报文段后,服务器B进入ESTABLISHED(已建立连接)状态。

4.2 TCP连接释放(四次挥手)

TCP原理与应用详解

刚开始释放连接时,客户机A和服务器B都处于ESTABLISHED(已建立连接)状态。首先A应用进程首先向A的TCP发出连接释放报文段,并且停止再次发送数据,主动去关闭TCP连接。A把连接释放报文段的报文首部FIN终止位设置为1,然后序号seq=u,这个序号就是前面传送过的数据的最后一个字节的序号加1。FIN报文段不携带数据,只消耗一个序号。接下来A就进入FIN-WAIT-1(终止等待1)状态,等待服务器B的确认报文段。

服务器B收到了释放报文段以后向客户机A发送确认报文段,确认序号是ack=u+1,然后发送自己的序号seq=v。这个V上面的u一样,就是B传送过的数据的最后一个字节的序号加1。然后B就进入了CLOSE-WAIT(关闭等待)的状态,这样就相当于是关闭了A->B这个方向的连接,这个时候客户机只能接受B发来的数据,不能发送。所以下一步就是断开B->A方向上的连接。

A收到了B的确认报文段,然后A就转为了FIN-WAIT-2(终止等待2)状态。

经过关闭等待,B向A连接发送释放报文段,同样设置报文首部FIN终止位为1,B的序号变为seq=w(不是v主要是可能在关闭等待过程中可能发生了数据传送),确认序号ack=u+1,确认位设置为1,接下来,B就进入了LAST-ACK(最后确认)状态,等待A的确认。

A收到了B的连接释放报文段,需要对此发送确认报文段,设置确认位ACK=1,序号为u+1(第一次发送的链接释放报文消耗一个序号),确认序号ack=w+1,然后进入TIME-WAIT(时间等待)状态,这个时候并没有释放链接,通过时间等待计时器以后设置时间2MSL以后,A进入CLOSED(关闭)状态。最终A撤销了传输控制块TCB,结束了这次连接。

B收到A的确认报文段以后,就进入了CLOSED(关闭)状态,B同样撤销了传输控制块,结束了这次连接。并且因为时间等待的关系,B的结束要比A要早一点。

4.3 TCP释放链接的2MSL问题

这个MSL是最长报文段寿命,2MSL是设置给时间等待计时器的,一般来说,一个MSL是2分钟,所以2MSL就是4分钟,所以相当于一个客户机需要扽大概4分钟,然后进入CLOSED状态,才能开始建立下一个新的连接。

等待2MSL的目的是为了:

(1)保证四次挥手的时候客户机发送的最后一个ACK报文段能够到达服务器,如果丢失了,此时就会让服务器B重新向客户机A超时重传LAST+ACK报文段。然后客户机重传一次ACK确认报文段,重新启动时间2MSL等待定时器,这样才能确保客户机和服务器都进入CLOSED状态,防止因为客户机的ACK报文段的丢失导致服务器无法CLOSED。

(2)防止出现已失效的链接请求报文段出现在本次连接当中,客户机发送完ACK报文段,然后经过2MSL,就可以让本连接持续时间内所产生的所有的报文段都从网络当中消失。这样就可以使得下一个新的连接中不会出现这种旧的连接请求报文段。

4.4 常见的面试相关三次握手四次挥手问题

  1. 为什么会采用三次握手,若采用二次握手可以吗?

    采用三次握手是为了防止失效的连接请求报文段突然又传送到主机B,因而产生错误。失效的连接请求报文段是指:主机A发出的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新向主机B发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,主机A第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,但是此时主机A根本不会理会,主机B就一直在等待主机A发送数据,导致主机B的资源浪费。所以只能最少采用三次握手,两次握手会出现问题。采用了三次握手,A就不会像B的确认发出确认,这样B就知道A没有要求建立连接,B就不会发送数据了。

  2. 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

    原因是因为TCP是全双工模式,因此每个方向都需要一个FIN和ACK,当一端发送了FIN包之后,处于半关闭状态,此时仍然可以接收数据包。

    在建立连接时,服务器可以把SYN和ACK放在一个包中发送。

    但是在断开连接时,如果一端收到FIN包,但此时仍有数据未发送完,此时就需要先向对端回复FIN包的ACK。等到将剩下的数据都发送完之后,再向对端发送FIN,断开这个方向的连接。

    因此很多时候FIN和ACK需要在两个数据包中发送,因此需要四次握手

5. TCP/IP中的四种定时器


在TCP当中使用了四种定时器:

重传计时器

坚持计时器

保活计时器

时间等待计时器

  1. 重传定时器(Retransmission Timer): 为了控制丢失的报文段或丢弃的报文段,也是对报文段确认的等待时间,当TCP发送报文段,就创建这个待定报文段的重传定时器,当超时之前收到对报文段的确认,撤销计时器。若收到对报文段确认之前计时器超时,则重传报文,计时器被复位。

  2. 持续计时器(Persistent Timer): 持续计时器是在TCP的流量控制当中有提到,在流量控制当中,如果出现一种互相等待的死锁局面,这个时候就需要持续计时器,它专门为了对付零窗口通知设立的,当发送端收到零窗口确认,就启动持续计时器,当持续计时器截止期到的时候,这个时候发送端就会发送一个特殊的报文段,这个报文段叫做探测报文段,这个报文段只有一个字节的数据。探测报文段有序号,对方就在确认这个探测报文段的时候给出窗口值。如果窗口依然是零,那么收到这个报文段的一方就重新设置持续计时器,如果窗口不是零,就打破串口报文段丢失导致的死锁问题。

  3. 保活计时器(keeplive timer): 跟据TCP协议,当发送端和接收端都不主动释放一个TCP连接的时候,该连接将一直保持。即使一端出现了故障,由于另一端没有收到任何通知,TCP连接也会一直保持,这样就会造成TCP连接资源的浪费。所以有了保活定时器,保活计时器是每次在服务器接收到客户机发来的消息,就会被复位,超时通常设置为2小时,若服务器超过两小时还没有收到来自客户的信息,则就会发送探测报文段,若发送了10个探测报文段依然没有收到响应,服务器就认为客户到出问题,则终止链接,一次发送一个为75秒。

  4. 时间等待计时器(Time_Wait Timer): 时间等待计时器是在连接终止期使用,当客户TCP关闭连接的时候,此时并不认为这个链接就关闭了,此时必须经过设置时间的2MSL以后,才会进入关闭状态。剩下的上述关于2MSL有陈述,这里就不多说了。

评论

目前评论:0   

点击加载更多评