1. 确认应答机制
- TCP为每个字节的数据都进行了编号,即就是我们所说的序列号Seq。
- ACK就带有对应的确认序列号,就是为了告诉发送者,已经收到了哪些数据,下次要从哪里开始发送。
2. 超时重传机制
(1)情况一,主机A向主机B发送数据,但可能出现网络拥堵等情况,导致数据无法传输到主机B,因此A在等待一个特定的时间段后,还未收主机B的确认应答,就会重新发送数据。
(2)情况二, 主机A向主机B发送数据,但是主机B在确认应答的时候出现问题导致丢包,那么主机A在等待特定时间后,会进行数据的重新发送,但由于主机B事实上是收到数据的,重新发送会有重复数据,所以又可以应用到前面所说的序列号,做到去重效果。
(3)特定时间间隔的确定
- 最理想的情况下,要确保找到一个最短时间,并且在该时间内确认应答一定可以返回
- 如果超时时间太长会影响重传效率,时间太短会导致包的重复发送
- Linux、Windows中,以500ms作为一个单位每次判定超时重发的时间为500ms的整数倍,重发一次得不到应答,就等到2*500ms进行重传,仍不行的话就4*500ms,以指数形式递增,累积到一定重传次数,就判定是网络或者对端主机出现异常,会强制关闭连接。
3. 连接管理机制
(1)详细的三次握手建立连接与四次挥手释放连接过程,可以看上一篇的博客:图解TCP三次握手与四次挥手~
(2)客户端的状态转换
- CLOSED -> SYN_SENT:客户端调用connect,发送同步报文段SYN;
- SYN_SENT -> ESTABLISHED:connect调用成功,此时进入ESTABLISHED状态,开始进行数据的传输;
- ESTABLISHED ->FIN_WAIT_1:客户端进行close调用,向服务器发送结束报文,然后进入FIN_WAIT_1状态;
- FIN_WAIT_1 -> FIN_WAIT_2:当客户端收到服务器端对结束报文的响应,客户端就进入FIN_WAIT_2状态,然后等待服务器端的结束报文;
- FIN_WAIT_2 -> TIME_WAIT:客户端收到服务器端的结束报文,进入到TIME_WAIT状态,并发送最后一个ACK;
- TIME_WAIT -> CLOSED:客户端等待2MSL,进入CLOSED状态。
(3)服务器端的状态转换
- CLOSED -> LISTEN:服务器端调用listen进入LISTEN状态,监听等待客户端的连接请求;
- LISTEN -> SYN_RCVD:监听状态下收到连接请求,即同步报文段,会向客户端发送SYN确认报文和ACK;
- SYN_RCVD -> ESTABLISHED:客户端发回确认报文,服务器端就进入到ESTABLISHED,可以开始数据传输;
- ESTABLISHED -> CLOSE_WAIT:服务器端收到结束报文,回复报文并进入CLOSE_WAIT状态;
- CLOSE_WAIT -> LAST_ACK:处理完之前的数据,服务器端就要准备关闭连接,正式关闭时会发送FIN,并进入LAST_ACK,等待最后一个ACK到达;
- LAST_ACK -> CLOSED:服务器端收到客户端的ACK,彻底关闭连接。
4. 滑动窗口
-
前面提到的确认应答机制,对每一个发送的数据段, 都要给一个 ACK 确认应答, 收到 ACK 后再发送下一个数据段, 这样做有一个比较大的缺点, 就是性能较差。于是采用滑动窗口机制, 将一去一回的串行的网络传输转变为并行的收发数据 ,主要作用就是 提高网络传输效率 。
-
窗口:无需等待确认应答而可以继续发送数据的最大值。 窗口越大, 则网络的吞吐率就越高。
-
滑动:并行发送数据报时,需要收到ACK响应报文才能确认数据发送成功,而窗口的滑动与否以及滑动的位置,都是由ACK响应报文的下一个序号确定,具体是 滑动到ACK响应报文连续的最大确认序号 。
5. 流量控制
-
接收端处理数据的速度是有限的,若 发送端发的太快, 导致接收端的缓冲区被打满,此时持续 发送, 就会造成丢包、丢包重传等一系列连锁反应。因此 TCP 支持根据接收端的处理能力, 来决定发送端的发送速度。
-
流量控制具体实现:①接收端将接受缓冲区的大小放在TCP首部的“窗口大小”字段,和ACK一起发送,字段越大说明吞吐量越高;②接收端一旦发现自己的缓冲区将满,就会把窗口大小改成一个更小的值通知给发送端;③发送端接收到窗口,会减慢发送速度;④若接收缓冲区满了,窗口直接置为0,此时发送端不再发送数据,但是定期发送一个窗口探测数据段,让接收端把窗口大小反馈过来。
6. 拥塞控制
- 因为在开始阶段,我们并不了解当前网络状况,贸然发送大量数据会导致网络状况更差,所以使用慢开始机制,先看看网络状态,再适当增加传输速度。
- 此处引入了拥塞窗口的概念,拥塞窗口初始值为1,随后开始指数型增长,直到到达某个阈值后,变成线性增长。
- TCP开始启动时,慢启动阈值为窗口最大值,每次发生超时重传,阈值减半同时拥塞窗口置为1。
- 拥塞控制的实质即为:即可能快的传输数据,但是要避免给网络造成巨大压力的折中方案。
7. 延迟应答
- 如果接收数据的主机立即返回ACK应答,那么返回的窗口是很小的,但是我们知道,窗口越大网络的吞吐量就越大,传输效相应就越高,而最理想的状态就是保证网络不拥塞的情况下计量提高传输效率。
- 延迟应答原理就是:接到数据报,不马上响应ACK,等待一段时间后再应答,这样可以增加滑动窗口分大小,并提高网络吞吐量。
- 数量限制:每隔N个包应答一次;时间限制:超过最大延迟时间就应答一次;具体数量和超时时间是由操作系统决定,一般N取2,超时时间取200ms。
8. 捎带应答
- 实质上就是合并发送数据报,从而提高网络传输效率。
9. 粘包问题
(1)粘包问题出现原因
- TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
- 发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。
- 接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象.
(2)解决方法
- 实质是:明确两个包之间的边界
- 对于定长包,每次按照固定大小读取即可。
- 对于不定长包,①可在包头位置,约定一个包总长度的字段;②在包和包之间使用明确的分隔符,保证不和正文冲突即可。
10. 面向字节流
- 当创建一个TCP的socket时,会同时创建一个发送缓冲区和接收缓冲区。
- 调用write时,数据会先写入发送缓冲区,①如果发送字节数过长,会被拆分成多个TCP数据包发送出去;②如果发送字节数太少,就需要等待,等到缓冲区内数据长度差不多时,会发出去。
- 接收数据时,从网卡驱动程序到达内核的接收缓冲区,然后应用程序可以调用read从接收缓冲区取数据。
- 因为对于一个TCP连接来说,既可以读数据也可以写数据,那么就是全双工的。
11.TCP小结
(1)安全机制
- 确认应答机制:ACK+序号实现。
- 超时重传机制:TCP内部实现,动态计算,以单方向数据传输最大时间*2作为超时时间。
- 连接管理机制:三次握手建立连接与四次挥手释放连接。
- 流量控制:使用窗口大小字段,告诉发送端发送数据的大小。
- 拥塞控制:慢启动,指数增长到阈值开始线性增长。
(2)效率机制
- 滑动窗口:并行收发数据。
- 延迟应答:接收到数据报,等待一段时间再响应ACK。
- 捎带应答:合并发送数据报。
12.TCP与UDP的对比
对比 | UDP(用户数据报协议) | TCP(传输控制协议) |
有无连接 | 无连接 | 有连接 |
是否可靠 | 不可靠 | 可靠 |
传输方式 | 面向数据报 | 面向字节流 |
缓冲区 | 有接收缓冲区,无发送缓冲区 | 接收、发送缓冲区都有 |
首部开销 | 8字节 | 20字节 |
连接方式 | 一对一、一对多、多对多的交互通信 | 点到点 |