引言
在上一篇文章:《HTTP十六连问》 中,曾提到“HTTP2最大的缺陷在于它依然没有在实质性地解决队头阻塞的问题,只是把它交给了TCP层,也就是计算机网络所说的上层依赖下层的服务”。如果接下来被询问到TCP相关的问题,该如何回答呢?
那TCP是如何解决拥塞问题的?
TCP有拥塞控制,用到的算法可以用6个字概括:“慢启动、快重传”。
流量发送不仅由收发双方决定,还由真实的网络环境决定。
慢启动-快重传的算法如图所示:(图来源于《computer network》)
- 横坐标是时间的推移,单位是RTT(round trip time),纵坐标是当前发送的窗口大小
- 所谓慢开始,其实也不是真的慢,因为它是指数级增长的 ,只是从1开始,而不从发送方要求的值开始。
- 初始会设定一个阈值(threshold),窗口大小达到阈值后,转为线性增长(慢下来)
- 当窗口大小超过接收方所能承受的最大长度后,会发生丢包,于是这时发送窗口大小又会快速重新减少为初始值,这就是重传。
- 重传开始后,新的阈值会被设定为上次导致发生超时的最大窗口的一半。
- 这个过程会不断重复,保证流量窗口是不断伸缩,但又在可控范围内。
TCP还有什么特点呢?
面向连接的、可靠的、基于字节流传输
那可靠性除了体现在拥塞控制,你还能想到别的内容吗?
比如流量控制和差错控制、(序号+确认)——>保证有序性、定时器——>超时重传,保证完整性
但其实这些概念是贯穿多个层的,并不是某一层独有,往往是上层调用下层的服务,而且算法思想也是类似的。早在接触链路层时我就已经接触过流量控制和差错控制的概念了。
以下先说说在链路层中被介绍过的背景知识:
先说说差错控制:
- 对于发现错误和纠正错误,有检错码(奇偶校验、CRC校验等)和纠错码(汉明码能检错也能纠错)
- 对于发生错误后的重传,有滑动窗口协议,它分为三类:
- 停-等协议
- 回退n帧(发送方记录状态,重发出现错误那一帧往后的所有内容)
- 选择性重传(接收方记录状态,要求发送方发送出现错误的那一帧即可)
接下来说说流量控制: 其实流量控制和拥塞控制有一点像,但又有不同:
- 拥塞控制是一个全局性的问题,必须使整个网络的主机、路由器、线路等资源或能力相匹配,目的是保障子网能够正常地传输分组。
- 流量控制是一个一对一的问题,使发送方和接收方的能力匹配,通过一定的机制保证发送方发送的速度不至于淹没接收方。
流量控制的思路大致分为两类:
- 基于反馈的流控制
- 基于速率的流控制
前者是链路层中介绍的,用滑动窗口的机制去实现,但发送窗口的移动依赖于确认帧的到达;而后者是传输层中特有的特性,也就是TCP会采用的流控制方法。
具体流程是这样的:
- TCP的窗口大小是其缓冲区的尺寸,建立连接的双方都将分配一个缓冲区作为接收数据的 存放空间,并相互通知对方,此后,每次对接收数据确认的同时发布一个窗口公告(window advertisement),报告剩余窗口的大小,任何时刻,剩余的缓冲区空间的数量叫窗口大小。
- 发送方收到一个零窗口公告时,必须停止发送,直到接收方重新发送一个非零的窗
口公告,但有两种情况可以除外:
- 发送紧急数据,如允许用户终止(kill)当前正在远端机上运行的进程
- 发送方可以发送一个字节的数据段通知对方,要求接收方重申希望接收的下一字节及当前的窗口大小,以防止可能的窗口公告丢失而导致的死锁
下图完整地展现了这一过程:(图来源于《computer network》)
TCP和UDP的区别是什么?
TCP和UDP的协议字段不同,因为它们的目标不同。UDP字段只有四个部分。
- TCP可提供有连接的服务,有上述提到的拥塞控制、流量控制、差错控制等等,需要保证数据有序到达;UDP是无连接的,它不保证可靠的传输,不保证数据按顺序到达,甚至不保证它能到达。
- 另外,由于TCP需要建立连接,所以它是一对一的,而UDP可以是一对一,一对多,多对多的交互通信。
还有一些比较细微的点:
- TCP是流式传输的,UDP是逐包逐包发送。
(不知道这点和下图有没有联系,图源【计网复习随手记】(一)
- TCP 的数据大小如果大于 MSS(message segment size) 大小,则会在传输层进行分片;UDP 的数据大小如果大于 MTU(message transmission unit) 大小,则会在 网络层进行分片
TCP和UDP各自的应用场景?
- 有些服务是必须要保证可靠数据传输的,比如文件传输(使用FTP等)、远程登录(SSH)、HTTP/HTTPS等
- 像音视频这类,并不要求数据完整,偶尔一两帧发生错误或丢失不影响整体体验,但对实时性要求高(允许出错,但不允许延时),就基于UDP
- 像DNS用的就是UDP,支持HTTP3的QUIC也是基于UDP的
- 前面提到UDP可以一对多、多对多,因此可用于广播通信
TCP和UDP可以使用同一个端口吗?
结论就是:经过测试,是可以的。
但为什么是这样,要涉及到对一些抽象概念的理解。
要解答这个问题,首先得明确端口是什么。
直观地理解,在启动项目服务的时候,比如"http://localhost:8080" ,冒号后面的8080就是端口号。端口实际上是为了区分主机上的不同进程,比如A进程占用了a端口,B进程就不能再占用b端口了。端口号的划分是相对主机而言的,不同主机的端口号是相互独立的。
由上述表述可以明确一件事情:同一台主机的同一个端口不能被两个进程占用(但也有特例,父子进程)。
而TCP和UDP是进程吗?不是,它们是两种不同的协议,对应于两个不同的软件实体。
我的理解是在计算机网络中提到的进程又和操作系统的不太一样,这里的进程指的是应用层级别的运行中的程序,所以相对应地,TCP和UDP是在它之下的概念。
而在ip的协议字段中,有一个protocol字段,当为6时表示上层为TCP,17时为UDP。 (图片来源【计算机网络】网络层(二)ipv4头部分析
通过这个字段可以确定数据之后是发送给TCP/UDP这两个模块中的哪一个进行处理。但从这里开始,两者就已经分开了。虽然TCP的端口和UDP的端口都是端口,但它们是两个概念,是相互独立的,类似于有两个人都是叫小明,但他们并不是同一个人。
因此不会产生冲突。
关于UDP
UDP有差错控制吗?
UDP协议中有checksum字段,它能检错,但不能纠错。
UDP一定是不可靠的吗?
不,由它构建的应用可通过自身建立可靠性机制,比如Chrome用QUIC
那关于QUIC你能再详细说说吗?
它由Google在2012年研发及部署,并已在2021年被写入RFC9000标准。 QUIC有几大基本特性:
- 快速建立连接
- 基于速率的拥塞控制算法
- 差错控制
- 重传机制
因为有着和TCP很相似的特性,它被戏称为"TCP/2"
(它还保证了通信的前向安全:指用来产生会话密钥的长期密钥泄露出去,不会泄漏以前的通讯内容,具体措施是每次会话都创建一个新的通信密钥)
关于TCP的连接细节
TCP三次握手的流程?
面试时可以回忆这张图,重点描述这几个字段的状态变化。
- 为什么ack=seq+1?因为ACK可理解为“我同意接收,你上次是到seq,请你记住你下一次开始发送的位置,从seq+1开始”
- 其中的ACK和SYN指的是协议字段中的相应位置1;seq和ack则是32bits对应的域。
为什么是三次握手?
笔者初学计算机网络时,看完课本后曾写下了这篇文章【计算机网络】再谈传输层(一)杂谈:TCP为什么是三握四挥?不这样做会如何
里面列举了几种可能的连接失败的情况(虽然现在回头看发现不全)。
三次握手应该是经过多次验证能得出的最优解,它可以保证如下几点:
- 阻止重复历史连接的初始化
比如若网络拥堵导致初始连接请求没被接收,第二次又发送,后面新旧两次连接都到达了服务端,就可能导致服务端重复响应和连接
- 同步双方的初始序列号
见上述说的ACK的含义
- 第三次握手恰到好处地避免资源浪费
如果没有客户端的第三次握手,服务端得去发送请求询问是否已建立连接,如果这一过程因为网络阻塞重复多次,就会造成资源浪费
没有accept可以建立连接吗?
从上图可知,accept没有直接参与三次握手的过程,所以是可以的。
没有listen可以建立连接吗?
那要看是什么连接,有一种TCP自连接机制,指的是客户端自己和自己建立了连接,这种情况下不需要服务端参与,也不需要listen。
为什么需要TIME_WAIT?
参考两军问题,没有回应也是一种回应。能确保被动关闭的一方最终也能正确被关闭。
TIME_WAIT过多有影响吗?如何避免?
影响:占用端口资源(客户端)、系统资源(服务端)(CPU、内存等等)
措施:其实time_wait是一种好的设计理念,有一些强制措施,但治标不治本,最好的原则就是服务器不要主动断开连接,让客户端去断。
- 有个reuse和timestamp选项
- 有个buckets
- 通过SO_LINGER,发送RST来强制关闭连接,跳过TIME_WAIT
那什么时候服务器会主动断开连接呢?
- HTTP请求达到上限
- HTTP没有使用keep-alive或者keep-alive超时
建立连接后服务端宕机会发生什么?
服务端会发送FIN报文,接下来进行四次挥手操作。
为什么四次挥手还能正常执行? 因为TCP连接信息是由内核维护的,挥手过程也是通过内核完成,出现故障后TCP连接资源将会被内核回收,并完成挥手操作。
如何应对连接后客户端宕机这种情况?
参考上面提到的keep-alive机制,超时服务器会自动断连(比如ssh上去服务器如果没有设置seconds between keep-alive,长时间没操作后就会断开连接)
参考文献
- 《computer network the fifth edition》
- 《计算机网络自顶向下方法》
- 小林coding----TCP三次握手和四次挥手的面试题(2023最新版)