一、TCP协议

1、基本概念

TCP全称为 “传输控制协议(Transmission Control Protocol”), TCP协议是网络模型中传输层协议,为应用层程序提供可靠的数据传输,因此协议也相对复杂一些;

2、TCP协议主要特点

(1)支持面向连接的传输服务

应用程序在使用TCP协议所能提供的服务传送数据之前,必须在源端口与目的端口之间建立一条TCP传输连接。TCP建立在不可靠的IP协议之上,IP协议不能提供任何可靠性保障机制,因此TCP协议的可靠性需要自己来解决。

(2)支持字节流的传输

流相当于一个管道,从一端放入什么内容,从另一端可以照样取出什么内容。表现了数据传输过程中不丢失、重复和乱序的特点。

(3)支持全双工通信

TCP协议允许通信双方的应用程序在任何时候都可以发送数据,通信的双方都有发送和接收缓冲区,数据的实际收发过程都由TCP协议控制。

(4)支持同时建立多个并发的TCP连接

根据应用程序的需要,TCP协议支持一个服务器与多个客户端同时建立多个TCP连接,也支持一个客户端同时与多个服务器端建立多个TCP连接,TCP协议软件将分别管理多个TCP连接。

(5)支持可靠的传输服务

TCP使用确认机制检查数据是否安全和完整的到达,并且提供重传/拥塞控制功能,
但是需要注意的是:一旦IP协议及以下层出现传输错误时,TCP协议只能不断进行重传。

3、TCP协议的报文格式

TCP协议段格式如下:
TCP/IP协议---TCP协议基础知识总结
字段说明:

字段 说明
源端口号和目的端口号 表示数据从哪里来,到哪里去,均为16位(2字节)
32位序号 一次TCP通信(建立到断开)过程中某一个传输方向上的字节流的每个字节的编号,它保证了TCP通信的有序性,解决网络包乱序的问题,由于有了这个编号,接收端可以根据这个序号进行确认,可以保证每个分段在原始数据包中的位置,初始***由自己定,而后绪的***由对端的ACK决定:SN_x = ACK_y (x的***=y发给x的ACK)
32位确认序号 用来对另一方发送来的TCP报文段的确认响应,其值是收到的TCP报文段的序号+1,也是对发送端下一次发报文段过来的序号,期望发送端以这个序号开始发送自己的分组,这样可以保证发送过来的报文是有序的,否则发送端不能确认之前的报文是否有被收到,而要决定是否重传。
4位首部长度 TCP实际报头长度是20~60字节
控制字段 紧急位URG=1,表示该报文段的优先级最高;确认位ACK=1,TCP建立连接之后发送的所有报文段都为1;推送位PSH,一端应用进程在输入一个命令之后,能够立即得到对方的响应,就将PSH置为1;复位位RST:当RST=1时,有两种含义:一是因为主机崩溃等原因造成TCP连接出错,需要释放连接,并重新建立连接;二是拒绝一个非法TCP报文或拒绝释放一个连接。同步位SYN:在连接建立时用来同步序号;终止位FIN:用来释放一个TCP连接
16位窗口大小 窗口字段值是准备接收下一个TCP报文段的接收端,通知即将发送报文段的发送端,下一次最多可以发送报文段的字节数,发送端将根据接收端通知的窗口值来调整自己发送窗口值的大小。
校验和 TCP校验和是必须的
紧急指针 当紧急标志URG=1时,这个位字段有效,这时的报文段中包括紧急数据
选项 选项字段多达40个字节

二、TCP连接建立与释放

1、TCP连接建立—–“三次握手”

TCP建立连接需要经过“三次握手”,这个过程可以描述如下:
TCP/IP协议---TCP协议基础知识总结
文字描述如下:
(1)最初的客户端TCP进程是处于“CLOSE”状态,当客户端准备发起一次TCP连接,首先向LISTEN状态的服务器端TCP进程发送第一个控制位SYN=1的“连接建立请求报文”,然后进入“SYN-SEND”状态
(2)服务器端在接收到“连接建立请求报文”之后,如果同意连接,就向客户端发送第二个控制位SYN=1,ACK=1的“连接建立请求确认报文”,这是服务器进入“SYN-RCVD”状态。
(3)在接收到“连接建立请求报文确认”之后,客户端发送第三个控制位ACK=1“连接建立请求确认报文”,这是客户端进入“ESTABLISHED”状态,服务器端在接收ACK报文之后,也进入“ESTABLISHED”状态,TCP连接建立成功。

2、数据传输

数据传输流程图如下:
TCP/IP协议---TCP协议基础知识总结
文字描述:
(1)当客户进程和服务器进程之间的TCP传输连接建立之后,客户端的应用进程与服务器进程就可以使用这个连接,进行全双工的字节流传输。
(2)为了保证TCP工作正常、有序地进行,TCP设置了保持计时器,用来防止TCP连接处以长时期空闲。
(3)当服务器端收到客户端的报文时,就将计时器复位
(4)如果服务器端过了设定的时间没有收到客户端的信息,它就发送探测报文,如果发送10个探测报文还没有响应,就假设客户端出现故障,进而终止连接。

3、TCP释放连接—–“四次挥手”

TCP释放连接“四次挥手”示意图如下:
TCP/IP协议---TCP协议基础知识总结
文字描述:
(1)当客户准备结束一次数据传输,主动提出释放TCP连接时,进入“FIN-WAIT-1”状态。它向服务器端发送第一个控制位FIN=1的“连接释放请求”报文,并停止发送数据。
(2)服务器端在接收“连接释放请求”报文后,需要向客户端发送“连接释放请求确认报文”,表示对接收第一个链接释放请求报文确认。
此时,TCP服务器进程向高层应用通知客户端请求释放TCP连接,客户到服务器的TCP连接断开。
(3)服务器向客户端发送“释放连接请求报文”;
(4)客户端在收到FIN报文后,向服务器发送“连接释放请求确认”报文,表示对服务器“连接释放请求报文”的确认。

4、时间等待计时器的作用

为了保证TCP连接释放过程正常运行,TCP设置了时间等待计时器,当TCP关闭一个连接时,它并不认为这个连接马上就真正关闭,这时,客户端进入“TIME-WAIT”状态,需要再等待两个最长报文寿命(2MSL)时间之后,才真正进入“CLOSE”状态。

客户端与服务器端经过“四次挥手”之后,确认双方已经同意释放连接,客户端仍然需要等待2MSL时间,确保服务器在最后阶段发送给客户端的数据,以及客户端发送给服务器端最后一个“ACK”报文都能被正确的接收,防止连接释放失败。

三、TCP重传机制

TCP要保证所有的数据包都可以到达,所以,必需要有重传机制。
注意,接收端给发送端的ACK确认只会确认最后一个连续的包,比如,发送端发了A、B、C、D、F一共五份数据,接收端收到了,于是回ack C,然后收到了D(注意此时3没收到),此时的TCP会怎么办?我们要知道,因为正如前面所说的,SeqNum和ACK是以字节数为单位,所以ack的时候,不能跳着确认,只能确认最大的连续收到的包,不然,发送端就以为之前的都收到了。

1、超时重传机制

一种是不回ack,死等C,当发送方发现收不到C的ack超时后,会重传C。一旦接收方收到C后,会ack 回 D——意味着C和D都收到了。

但是,这种方式会有比较严重的问题,那就是因为要死等C,所以会导致D和F即便已经收到了,而发送方也完全不知道发生了什么事,因为没有收到Ack,所以,发送方可能会悲观地认为也丢了,所以有可能也会导致D和F的重传。
对此有两种选择:
(1)选择重传方式
只将丢失的字节序号通知发送端,发送端只需要重传丢失的报文,而不需要重传已经接收的报文段。
(2)拉回方式
也就是需要在第三个数据开始,不管之后的报文段接收是否正确,重传C、D、F这三个报文段。
这两种方式有好也有不好。第一种会节省带宽,但是慢,第二种会快一点,但是会浪费带宽,也可能会有无用功。但总体来说都不好。因为都在等timeout,timeout可能会很长。

2、快速重传

这个机制不以时间为驱动,而是以数据来重传!如果接收端包收包没有连续到达,就ACK最后那个可能被丢了的包,如果发送方连续收到接收端3次相同的ack,就重传。
例如:如果发送方发出了1,2,3,4,5份数据,第一份先到送了,于是就ack回2,结果2因为某些原因没收到,3到达了,于是还是ack回2,后面的4和5都到了,但是还是ack回2,因为2还是没有收到,于是发送端收到了三个ack=2的确认,知道了2还没有到,于是就马上重转2。然后,接收端收到了2,此时因为3,4,5都收到了,于是ack回6。

四、TCP流量控制

如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。
(1)当接受方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失
(2)通过窗口来控制 (窗口大小字段越大, 说明网络的吞吐量越高)
所以,简单来说,就是接收方处理不过来数据的时候,就把窗口缩小,并把窗口值告诉发送端。
那么接收端如何把窗口大小告诉发送端呢?
在第一点讲解TCP首部中, 有一个16位窗口字段, 就是存放了窗口的大小信息。

五、TCP窗口与拥塞控制

TCP的拥塞控制由4个核心算法组成:“慢启动”(Slow Start)、“拥塞避免”(Congestion voidance)、“快速重传 ”(Fast Retransmit)、“快速恢复”(Fast Recovery)。

1、慢开始算法

当主机开始发送数据时,如果立即所大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。因此,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd 设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。用这样的方法逐步增大发送方的拥塞窗口 cwnd ,可以使分组注入到网络的速率更加合理。

2、拥塞避免算法

让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

3、拥塞控制具体过程为

(1) 当TCP连接进行初始化时,把拥塞窗口cwnd置为1。前面已说过,为了便于理解,图中的窗口单位不使用字节而使用报文段的个数。慢开始门限的初始值设置为16个报文段,即 cwnd = 16 。

(2)在执行慢开始算法时,拥塞窗口 cwnd 的初始值为1。以后发送方每收到一个对新报文段的确认ACK,就把拥塞窗口值另1,然后开始下一轮的传输(图中横坐标为传输轮次)。因此拥塞窗口cwnd随着传输轮次按指数规律增长。当拥塞窗口cwnd增长到慢开始门限值ssthresh时(即当cwnd=16时),就改为执行拥塞控制算法,拥塞窗口按线性规律增长。

(3)假定拥塞窗口的数值增长到24时,网络出现超时(这很可能就是网络发生拥塞了)。更新后的ssthresh值变为12(即变为出现超时时的拥塞窗口数值24的一半),拥塞窗口再重新设置为1,并执行慢开始算法。当cwnd=ssthresh=12时改为执行拥塞避免算法,拥塞窗口按线性规律增长,每经过一个往返时间增加一个MSS的大小。

强调:“拥塞避免”并非指完全能够避免了拥塞。利用以上的措施要完全避免网络拥塞还是不可能的。“拥塞避免”是说在拥塞避免阶段将拥塞窗口控制为按线性规律增长,使网络比较不容易出现拥塞。

六、关于TCP连接与释放的常见问题

1、为什么是三次握手而不是两次握手?

采用三次握手是为了防止已连接的请求报文段又传送到服务器,造成服务器崩溃。
假设只有两次握手,连接时,第二次丢失,服务器认为连接成功,而客户端认为连接失败,继续发送连接请求,服务器就会收到SYN的洪水攻击。

2、TCP释放连接时为什么是四次挥手?

由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行被动关闭。
假设在断开连接时,如果一端收到FIN包,但此时仍有数据未发送完,此时就需要先向对端回复FIN包的ACK。等到将剩下的数据都发送完之后,才能向对端发送FIN,断开这个方向的连接。
因此很多时候FIN和ACK需要在两个数据包中发送,则需要四次握手。

相关文章: