紧跟Linux_网络_传输层协议 TCP/UDP继续补充

1. TCP通信时滑动窗口(效率)

TCP在通信时存在确认应答机制,如果收到ACK后再发送下一个报文。类似串行发送,效率太低。

TCP在发送消息时,一次发送多条数据就可以大大提高性能,这就是TCP滑动窗口。(多条发送时间重叠在一起,类似多线程发送)

注意:TCP在发送数据时不能将数据一次全部发给对端,因为需要考虑对端接受缓冲区的大小

滑动窗口:
发送方不用等待ACK一次发送数据的最大量,滑动窗口大小与对端接受缓冲区的大小有关。

在这里插入图片描述

注意:

  1. 窗口大小:表示的对方接受能力,衡量的是接受缓冲区的剩余大小

  2. 滑动窗口:在自己的发送缓冲区限定一块空间可以直接发送不需要ACK。当发送的数据收到响应且对方接受缓冲区还有空间时,窗口向后滑动。

  3. 窗口一定是向右移动或者不移动。不可能向左移动,因为窗口左边一定是已经接受到ACK的数据

  4. 滑动窗口实际是环形缓冲区,窗口外的数据可以被覆盖,窗口内的数据要保存起来,为了防止丢包等重传问题。

但是TCP报文到达对端不一定是有序的,可能窗口内的报文先ACK或者窗口内的报文丢包

当窗口丢包时:

  • 可能是响应报文丢包,此时影响不大,因为可以根据窗口其他ACK来确认

根据TCP报头中的确认序号(发送报文的末端序列号+1,告知对方发送报文的末端序列号前的数据已经收到,下次发送从发送报文的末端序列号+1处开始发送)
eg:
在这里插入图片描述
因为窗口报文一起发给对端,所以发送端虽然只接收到一次报文,但根据第二次响应ACK的2001可以推断出0-1000对端已经收到了。直接从2001序号开始发送新的报文,同时窗口开始移动。


  • 丢包还可能存在在报文发送时丢包的情况

在这里插入图片描述

  1. 当某段报文丢包时例如1001-2000,此时发送端会一直收到ACK:1001
  2. 当收到三次ACK:1001时发送端会补发1001-2000段数据
  3. 设ACK:1001收到了三次, 当这次补发报文收到时ACK5001,因为5000前接收端已经收到(接受缓冲区)(快重传机制)
    在这里插入图片描述
    注意:当收到ACK 1001次数少与3次则无法触发快重传机制,就使用超时重传机制。

2. 流量控制(可靠性)

数据传输过程中,如果发送方发送数据的速度太快,接受方的接受缓冲区会满。如果不加处理,会因为接受缓冲区被打满而导致丢包。

TCP支持根据接受缓冲区的大小来决定发送数据的速度,这个机制称为流量控制。

  1. 接受端将接收缓冲区大小放入TCP报头中的 窗口大小字段上,通过ACK告诉发送端。
  2. 窗口大小字段越大,代表网络吞吐量越大。
  3. 当发送端收到ACK,其中窗口大小比较小时,会减少发送报文速度。(通过减少滑动窗口大小来减少速度
  4. 如果ACK报头中窗口大小为0,会停止发送报文,但会定期发送一个窗口探测数据段来获取接受端的缓冲区大小。

16位窗口大小为65535字节,但TCP报头上还存在选项字段(扩大因子M),实际窗口大小=16位窗口大小<<M

注意:在握手阶段,两端就已经协商了双方的接受缓冲区的大小。防止第一次数据通信时缓冲区越界。

3. 拥塞控制(慢启动)

当网络发送数据时出现大量丢包时,不是正常现象。可能是网络出现问题,可能网络太拥堵。

此时如果再进行丢包重传,只会加重网络的负担,不可取。

拥塞控制相关策略:
此时网络中的所有TCP采用慢启动机制,发送端会尽量不发送数据,一段时间后再发送少量数据。等到网络流畅后再进行正常发送。

拥塞控制这里又引入拥塞窗口:

  • 窗口大小:对端接受缓冲区剩余大小。
  • 滑动窗口:发送缓冲区限定一块空间可以直接发送不需要ACK
  • 拥塞窗口:一次发送端发送的数据量大于拥塞窗口值时,可能会引发网络拥堵。

发送开始时拥塞窗口大小定义为1,每次收到ACK应答时拥塞窗口会增大(指数增长)。每次接收端ACK报文中的窗口大小将于拥塞窗口数值进行比较,取较小的值作为发送端发送数据的大小。(实现慢启动)指数级增长为了尽快恢复通信。

指数增长到一定程度(慢启动阈值)后改为线性增长

慢启动阈值与上一次发生网络阻塞时阻塞窗口的大小有关(一半阻塞窗口的大小)在这里插入图片描述
滑动窗口大小=min(对端接受能力,拥塞窗口大小)

4. 延迟应答

接收端在接收到对端发送的报文后,根据确认响应机制ACK报文有窗口大小字段。

窗口大小字段越大代表网络吞吐量越大,所以接受端为了提高窗口大小字段,会延迟发送响应报文,等待应用层将缓冲区数据尽可能读取完毕在进行响应。(不会导致超时导致重传)

注意:

  1. 不是所有报文都会进行延迟应答,每隔N个报文进行一次延迟应答
  2. 具体N的大小以及超时时间根据操作系统而定。

5. 捎带应答(提高通信效率)

确认应答机制,接受端在ACK时可以携带要给发送端发送的数据。

ACK报文既有确认应答作用,还有发送数据的能力。提高通信效率

6. TCP常见问题

字节流

创建TCP的sock时,在内核创建发送和接受缓冲区。

发送端上层调用write。数据写入发送缓冲区,但写入缓冲区没有格式要求,可以一次写入100字节,也可以循环多次写入100字节数据。

接收端调用read函数阻塞等待接受缓冲区数据就绪。读取缓冲区数据没有格式要求,可以循环多次读取100字节,也可以一次读取100字节。

这就是面向字节流

粘包

当发送方将报文发送到对端接受缓冲区后,对端应用层按流式读取 接受缓冲区时读取方式和协议类型有关(eg:http协议按行读取),但如果上层不按照对应协议方式读取,可能应用层读取报文时不是完整的报文。这种现象就叫做粘包。

解决方法:明确报文与报文之间的边界

  1. 定长报文
  2. 特殊字符作为报文边界(http协议‘\n’)
  3. 自描述+定长/特殊字符(http协议’\n’+Content-Length字段)

UDP是定长报头+自描述(8字节报头长,16位UDP长度)所以不存在粘包问题

但基于TCP的应用层可能存在粘包问题:因为TCP面向字节流,TCP不维护报文之间的边界,报文与报文的分离需要应用层来做。

TCP异常

进程终止:进程终止后会释放文件描述符会关闭,可以发送FIN报文,正常进行四次挥手,正常退出连接。

机器重启:操作系统会终止所有进行,与进程退出一样,自动进行四次挥手。

拔网线:服务器无法迅速得知客户端掉线,客户端长时间不访问服务器,服务器向客户端发送数据,尝试多次后断开连接。(基于保活定时器的心跳机制,一般由应用层代码实现)

7. TCP总结

提高效率方面:

  1. 滑动窗口
  2. 快速重传
  3. 延迟应答
  4. 捎带应答

可靠性方面

  1. 校验和
  2. 序列号(按序到达)
  3. 确认应答
  4. 超时重发
  5. 连接管理
  6. 流量控制
  7. 拥塞控制

8. 半连接队列与全连接队列

针对的是监听listen函数的第二个参数LISTNUM
在这里插入图片描述
TCP是有连接拒绝策略,listen第二个参数为TCP底层可以连接的个数(全连接个数)

全连接队列(accept队列):用来保存已经建立好连接(ESTABLISHED状态),但是应用层没有调用accept函数将连接取走

全连接队列的长度由listen函数的第二个参数而定(全队列长度=listen第二个参数数值+1)

如果全连接队列满,如果此时又建立新连接,此时连接不会建立成功,而是处于半连接状态(SYN_RECV状态)
在这里插入图片描述
半连接队列:用来保存SYN_RECV状态和SYN_SEND状态的连接请求。长度由系统控制(半连接长度算法)。

系统维护全连接和半连接队列为了保证服务器可以最大限度的工作。

但是队列的长度不能太长,因为维护队列需要成本,同时客户端等待时间太长,维护长连接不如将资源提高服务器处理速度。

连接建立过程:
在这里插入图片描述

SYN洪水攻击使服务器无法正常提供服务

通过向服务器大量发送SYN报文,服务器SYN+ACK后,发送方不再ACK回去。导致半连接无法转移到全连接队列,最后半连接队列满,正常客户端无法再向服务器发送连接建立请求报文,因为半连接队列已满。使服务器无法提供服务。

Logo

更多推荐