TCP传输控制协议
TCP协议是一种面向连接的、可靠的字节流服务。TCP协议提供了多种机制来保证数据传输的可靠性。
1 .TCP报文格式
16位源端口号 | 16位目的端口号 | |||||||
---|---|---|---|---|---|---|---|---|
32位序列号 | ||||||||
32位确认号 | ||||||||
4位首部长度 | 保留(6位) | URG | ACK | PSH | RST | SYN | FIN | 16位窗口大小 |
16位TCP检验和 | 16位紧急指针 | |||||||
选项(若有) | ||||||||
数据(若有) |
源端口:标识主机上发起传送的应用程序。
目的端口:标识主机上传送要到达的应用程序。
(TCP协议通过使用"端口"来标识源端和目标端的应用进程。 端口号可以使用0到65535之间的任何数字。在收到服务请求时,操作系统动态地为客户端的应用程序分配端口号。)
序号字段: 本报文段所发送的数据的第一个字节的序号。
确认序号: 期望收到对方的下一个报文段的数据的第一个字节的序号。
首部长度:因为TCP选项字段长度可变,所以需要首部长度这个值。
标志位字段各字段含义如下:
· URG:紧急比特(urgent),当URG=1时,表明紧急指针字段有效,代表该封包为紧急封包。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据), 且紧急指针字段也会被启用。
· ACK:确认比特(Acknowledge)。只有当ACK=1时确认号字段才有效,代表这个封包为确认封包。当ACK=0时,确认号无效。
· PSH:(Push function)若为1时,代表要求对方立即传送缓冲区内的其他对应封包,而无需等缓冲满了才送。
· RST:复位比特(Reset) ,当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
· SYN:同步比特(Synchronous),SYN置为1,就表示这是一个连接请求或连接接受报文,通常带有 SYN 标志的封包表示『主动』要连接到对方的意思。。
· FIN:终止比特(Final),用来释放一个连接。当FIN=1时,表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
窗口字段用来控制对方发送的数据量,可以告知对方目前本身有的缓存还可以接收封包。
检验和字段:当数据要由发送端送出前,会进行检验,并将该动作的检验值标注在这个字段上。
紧急指针字段:URG = 1 时才会产生作用。可以告知紧急数据所在的位置(紧急指针指出在本报文段中的紧急数据的最后一个字节的序号)。
选项:TCP首部可以有多达40字节的可选信息,用于把附加信息传递给终点,或用来对齐其它选项。
重要注意点:
1、复位字段
TCP首部的RST位是用于复位的。无论合适一个报文端发往相关的连接出现错误,TCP都会发出一个复位报文段。主要分为以下三种情况:
(1)到不存在的端口的连接请求;
(2)异常终止一个连接;
(3)检测半打开状态。
2、最大报文段长度(MSS)
选项字段最常见的字段是最大报文段长度(MSS)字段,它表示TCP传往另一端的最大数据块的长度,也就是TCP报文段数据的最大长度。对于一个以太网来说,MSS值取为1460字节,一般是最大传输单元(MTU)1500字节减去20字节的TCP首部和20字节的IP首部。
2. TCP连接的建立与终止
2.1 三次握手与四次挥手
图2.1 TCP连接的建立与终止
TCP连接的建立是通过三次握手实现,连接的终止要经过四次握手,实现过程如上图所示。
建立连接协议
(1) 请求端发送一个SYN段指明客户打算连接的服务器的端口,以及初始序号(ISN),这个SYN报文段为报文段1。
(2) 服务器端发回包含服务器的初始序号的SYN报文段(报文段2)作为应答。同时将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认。一个SYN将占用一个序号。
(3) 客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认(报文段3)。
2.2半关闭状态
TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力,这就是TCP的半关闭。
客户端发送FIN,另一端发送对这个FIN的ACK报文段。当收到半关闭的一端在完成它的数据传送后,才发送FIN关闭这个方向的连接,客户端再对这个FIN确认,这个连接才彻底关闭。
2.3 等待定时器(2MSL连接)
时间等待TIME_WAIT状态也称为2MSL等待状态。MSL是每个TCP必须选择一个报文段最大生存时间。它是任何报文段被丢弃前在网络的最长时间。
时间等定时器的处理原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2MSL。这样可以让TCP再次发送最后的ACK以避免这个ACK丢失(另一端超时并重发最后的FIN)。这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间,定义这个连接的插口不能被使用。
2.4 同时打开与同时关闭
同时打开就是两个应用程序同时彼此执行主动打开,对于同时打开它仅建立一条连接而不是两条连接。两端几乎在同时发送SYN,并进入SYN_SENT状态。当每一端收到SYN时,状态变为SYN_RCVD,同时他们都再发SYN并对收到的SYN进行确认。当双方都收到SYN及相应的ACK时,状态都变为ESTABLISHED。一个同时打开的连接需要交换4个报文段,比正常的三次握手多了一次。 如图2.2。
图2.2 同时打开
同时关闭的基本流程是:当应用层发出关闭命令,两端均从ESTABLISHED变为FIN_WAIT_1。这将导致双方各发送一个FIN,两个FIN经过网络传送后分别到达另一端。收到FIN后,状态由FIN_WAIT_1变为CLOSING,并发送最后的ACK。当收到最后的ACK,状态变为TIME_WAIT。同时关闭和正常关闭的段减缓数目相同。
图2.3 同时关闭
3.TCP的超时与重传
TCP协议使用超时重发的重传机制 ,即: TCP每发送一个报文段,就对此报文段设置一个超时重传计时器 。此计时器设置的超时重传时间 RTO应当略大于TCP报文段的平均往返时延RTT, 当超过了规定的超时重传时间还未收到对此TCP报文段的预期确认信息,则必须重新传输此TCP报文段 。
3.1 往返时间RTT
RTT一般指在发送一个带有特别序号的字节和接受到包含该字节的确认之间的时间,TCP超时和重传机制最重要的就是对一个给定连接的往返时间(RTT)的测量。由于路由器和网络流量均会变化,因此TCP应该跟踪这些变化并相应地改变超时时间。首先TCP必须测量在发送一个带有特别序号地字节和接收到包含该字节地确认之间的RTT。
3.2 超时重传时间RTO
超时重传时间RTO的初始化是由公式决定的,例如最初的公式,初始的值应该是1。而修正公式,初始RTO应该是A+4D。
当数据正常传输的情况下,RTO的计算会依据最新的RTT的测量值来进行更新,并重开重传定时器,来保证下一个数据被顺利传输。
对于RTO时间的计算要注意的是:重传的情况下,RTO不用上面的公式计算,而采用一种叫做“指数退避”的方式,重传后的RTO取旧的重传时间的2倍。例如:当RTO为1S的情况下,发生了数据重传,就用RTO=2S的定时器来重新传输数据,下一次用4S。一直增加到64S为止。
4.滑动窗口机制
滑动窗口机制是TCP可靠传输中较为重要的一个机制。首先“窗口”的定义是对应的是一段可以被发送者发送的字节序列,其连续的范围称之为“窗口”;其次“滑动”则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序“滑动”。
发送窗口是发送缓存中的一部分,是可以被TCP协议发送的那部分,其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区;
发送窗口中包括有四个概念:已发送并收到确认的数据(不再发送窗口和发送缓冲区之内)、已发送但未收到确认的数据(位于发送窗口之中)、允许发送但尚未发送的数据以及发送窗口外发送缓冲区内暂时不允许发送的数据;
每次成功发送数据之后,发送窗口就会在发送缓冲区中按顺序移动,将新的数据包含到窗口中准备发送;
我们以一个例子来说明,TCP建立连接的初始,B会告诉A自己的接收窗口大小,比如为‘20’,如图3.1,字节31-50为发送窗口。
图3.1 A的发送窗口
A发送11个字节后,发送窗口位置不变,B接收到了乱序的数据分组:
图3.2 A发送11个字节
只有当A成功发送了数据,即发送的数据得到了B的确认之后,才会移动滑动窗口离开已发送的数据;同时B则确认连续的数据分组,对于乱序的分组则先接收下来,避免网络重复传递:
图3.3 A的窗口向前滑动
图3.4 A的可用窗口为0
5.拥塞控制
网络中的链路容量和交换结点中的缓存和处理机都有着工作的极限,当网络的需求超过它们的工作极限时,就出现了拥塞。拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。常用的方法就是:慢开始、拥塞控制、快重传、快恢复。
5.1 慢启动与拥塞避免算法
两种算法都需要对每个连接维持两个变量:一个拥塞窗口cwnd和一个慢启动门限ssthresh。
\1. 发送方维持一个叫做“拥塞窗口”的变量,该变量和接收端口共同决定了发送者的发送窗口;
\2. 当主机开始发送数据时,避免一下子将大量字节注入到网络,造成或者增加拥塞,选择发送一个1个报文段长度的试探报文;
\3. 当收到第一个报文段长度的数据的确认后,就发送2个报文段长度的报文;
\4. 若再次收到2个报文段长度的确认,则发送4个报文段长度,依次递增2的指数级;
\5. 最后会达到一个提前预设的“慢开始门限”,比如24,即一次发送了24个报文段长度的分组,此时遵循下面的条件判定:
1)cwnd <= ssthresh,继续使用慢开始算法;
2)cwnd > ssthresh,停止使用慢开始算法,改用拥塞避免算法。
\6. 所谓拥塞避免算法就是:每经过一个往返时间RTT就把发送方的拥塞窗口+1,即让拥塞窗口缓慢地增大,按照线性规律增长;
\7. 当出现网络拥塞,比如丢包时,将慢开始门限设为原先的一半,然后将cwnd设为1,执行慢开始算法(较低的起点,指数级增长);
图5.1 慢开始与拥塞避免举例
5.2 快速重传和快速恢复算法
在实际传输过程中如果我们一连串收到3个或以上的重复ACK,就非常可能是一个报文段丢失了,于是我们就重传丢失的数据报文段,而无需等待超时定时器溢出,这就是快重传算法。而快恢复算法就是在重传后不执行慢开始算法而是执行拥塞避免算法(高起点,线性增长),具体流程如下。
(1) 当收到第3个重复的ACK时,将ssthresh设置为当前拥塞窗口cwnd的一半,重传丢失的报文段,设置cwnd为ssthresh加上3倍的报文段大小。
(2) 每次收到另一个重复的ACK时,cwnd增加1个报文段大小并发送一个1个分组,如果允许的话。
(3) 当下一个确认新数据的ACK到达时,设置cwnd为ssthresh,这个ACK应该时在进行重传后的一个往返时间内对步骤1重重传的确认。另外,这个ACK也应该是对丢失的分组和收到的第一个重复的ACK之间的所有中间报文段的确认。
置cwnd为ssthresh加上3倍的报文段大小。
(2) 每次收到另一个重复的ACK时,cwnd增加1个报文段大小并发送一个1个分组,如果允许的话。
(3) 当下一个确认新数据的ACK到达时,设置cwnd为ssthresh,这个ACK应该时在进行重传后的一个往返时间内对步骤1重重传的确认。另外,这个ACK也应该是对丢失的分组和收到的第一个重复的ACK之间的所有中间报文段的确认。