什么是 TCP 协议?
首先,TCP 协议是位于
传输层
的协议,是面向连接的
、可靠的
流协议
TCP 为了提高可靠性传输,实行顺序控制
或重发控制
。此外还有流量控制
、拥塞控制
、提高网络利用率
等众多功能
下面,就从 TCP 协议的这些特点说开去:
可靠性
TCP 协议是如何实现传输过程中的可靠性,又是怎么实现的?
一句话概括:TCP 通过 校验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现可靠性传输。
接下来,将引入包的传递过程,来带入这些概念:
ack - 校验和
客户端和服务端之间通过校验随机数+1,来确认连接
ACK - 确认应答
客户端和服务端使用确认应答 ACK 来知道二者的连接请求。
三次握手
TCP 是提供面向连接的通信传输。面向连接指的就是在数据通信开始之前先建立连接,确保传输通道的连通性。
而所谓三次握手就是建立一个 TCP 连接时需要 客户端和服务端总共发送三个包以确认连接的建立
这里引入三次握手来解释相关概念:校验和(ack)&& 确认应答(ACK)
流程图:
第一次握手:客户端将标志位 SYN = 1
,随机生成一个值 seq = j
,并将该数据包发送给服务端,客户端进入 SUN_SENT
状态,等待客户端的确认。
第二次握手:服务端接收到 SYN = 1
的数据包后,明确客户端请求建立连接,服务端将标志位SYN = 1、ACK=1
,随机生成一个随机数 seq=k
,校验和 ack=j+1,并将该数据包发送给客户端以确认连接请求,服务器进入SYN_RCVD
状态。
第三次握手:客户端收到确认后,检查检验和 ack = j+1
,ACK=1。如果正确将标志位 ACK = 1 。校验和 ack = k+1,并将该数据包发送给服务器端,服务器端检查 检验和 ack = k+1,ACK=1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED
状态,完成三次握手,随后便可以开始通信了。
序列号
在数据的传输中,可能存在
数据包丢失
或者未收到确认应答
的情况,此时为了实现可靠传输
,就会触发重发机制。
但是,也会有部分原因导致确认应答延迟到达,数据包实际上已经到达来服务端,那么服务端就会反复的接收到相同的数据包,为了避免这种情况,就会有重复控制功能。
上述确认应答机制、重发控制以及重复控制等功能都可以借助序列号来实现。
序列号是按顺序给发送数据的每一个字节(8位字节)都标上号码的编号。将自己下一步应该接收的序列号作为确认应答返送回去。
通过序列号和确认应答号,TCP 就可以实现顺序传输和可靠传输
重发超时如何确定
当发送端发送数据后,会有一个等待确认应答到来的特定时间间隔。若超过了这个时间仍未收到确认应答,发送端将数据进行数据重发。
然而这个重发超时时间的确定是根据当前的网络环境确认的,随着网络环境的不同而有所变化。
TCP 要求不论处在何种网络环境下都要提供高性能通信,并且无论网络拥堵情况发生何种变化,都必须保持这一特性。
它在每次发包时都会计算往返时间
及其偏差
。
重发超时的值就是比往返时间
和偏差
相加大一点的值,由于数据包的分段是经过不同路线到达的,所以网络环境的往返时间可能会产生大幅度的摇摆。
TCP/IP 的目的就是即使在这种环境下也要进行控制,避免流量的浪费。
连接管理
TCP 提供面向有连接的通信传输。面向有连接的是指在数据通信开始之前先做好通信两端之间的准备工作。
这里通常是指三次握手和四次挥手
TCP 发送数据的单位:段
在建立 TCP 连接的同时,也可以确定发送数据包的单位,我们称为最大消息长度(MSS: Maximum Segment Size)。
最理想的情况是,最大消息长度正好是 IP 中不会被分片处理的最大数据长度。
MSS 的计算方式
MSS 是在三次握手的时候,在两端主机之间被计算出。两端主机在建立连接的请求时,会在 TCP 首部中写入 MSS 选项,告诉对方自己的接口能够适应的 MSS 大小。
MSS 的大小就会在两者之间选择一个较小的值。
窗口控制提高速度
TCP 以 1 个段为单位,每发送一个段就进行一次确认应答的处理。但是这样传输的话,包的往返时间越长性能也就越低。
为了解决这个问题,TCP 就引入了窗口这个概念。即使在往返时间较长的情况下,它也能控制网络性能的下降。
确认应答不再是以每个分段,而是以更大的单位进行确认,转发时间将会被大幅度的缩短
重发控制
窗口控制中的重发控制,是以序列号进行管理的,当数据包丢失后,发送端会根据接收端序列号来进行重发
流控制
为了防止网络流量的无端浪费(接收端数据的处理),TCP 提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量。
接收端告诉发送端自己接收的数据大小,实际上就是该窗口大小。
拥塞控制
一般来说,计算机网络都处在一个共享的环境,因此也有坑因为其他主机之间的通信使得网络拥堵。
所以,如果一开始发送端就发送一个特大的数据包,可能会导致整个网络的瘫痪。
为了防止这个问题,TCP 在通信一开始时,就会通过一个叫做慢启动的算法得出的数值,对发送数据量进行控制。
首先,为了在发送端调节所要发送的数据的量,定义了一个叫做拥塞窗口
的概念。在慢启动的时候,将这个拥塞窗口的大小设置为一个数据段(1 MSS)发送数据,
之后每收到一次确认应答(ACK),拥塞窗口的值就加一。
不过,随着包的每次往返,拥塞窗口也会以 1、2、4 等指数函数的增长,拥堵状况激增甚至导致网络拥塞的发生。为了防止这些,又引入了慢启动阈值的概念。
只允许按照特定比例放大拥塞窗口:
1 个数据段的字节数/拥塞窗口(字节)* 1 个数据段字节数
于是,当 TCP 通信开始以后,网络的吞吐量会 逐步上升,但是随着网络拥堵的发生吞吐量也会极速下降。
接着,会再次进入吞吐量慢慢上升的过程。因此所谓 TCP 的吞吐量的特点就像是在逐步占领网络带宽的感觉。
参考:1.「 图解 TCP/IP 」2. 「 TCP/IP 卷一 」