首先我们应该深刻理解网络4/7层模型,然后一起学习传输层的TCP
两个非常重要的网络协议:HTTP、TCP。这两个协议也是服务交互中使用最多的协议。
TCP协议特点
TCP是传输层协议,对应OSI网络模型的第四层传输层,特点如下:
- TCP协议是基于链接的,也就是传输数据前需要先建立好链接,然后在进行传输。
- TCP链接一旦建立,就可以在链接上进行双向的通信。
- TCP的传输是基于字节流而不是报文,将数据按字节大小进行编号,接收端通过ACK来确认收到的数据编号,通过这种机制,TCP协议能够保证接收数据的有序性和完整性,因此TCP能够提供可靠性传输。
- TCP还能提供流量控制能力,通过滑动窗口来控制数据的发送速率。滑动窗口的本质是动态缓冲区,接收端根据自己的处理能力,在TCP的header中动态调整窗口大小,通过ACK应答包通知给发送端,发送端根据窗口大小调整发送速度。
- 仅仅有流量控制能力还不够,TCP协议还考虑到了网络问题可能会导致大量的重传,进而导致网络情况进一步恶化,因此TCP还提供拥塞控制。TCP处理拥塞控制主要用到了慢启动、拥塞避免、拥塞发生、快速恢复四个算法,有兴趣可以进一步了解。
除了TCP协议的特点,还可以进一步了解TCP协议的报文状态、滑动窗口的工作流程、keepalive的参数设置和Nagel算法的规则等一些细节。
另外还有典型的TCP协议问题,例如特定场景下Nagel和ACK延迟机制配合使用可能会出现delay40ms超时后才回复ACK包问题。
聊一聊TCP的三次握手建连和四次挥手断连
1. 详解三次握手建连
接下来看TCP建连的三次握手。TCP是基于链接的,所以在传输数据前需要先建立链接,TCP在传输上是双向传输,不区分Client和Server端,为了便于理解,我们把主动发起建连请求一端称为Client端,把被动建连的一段称为Server端。
如下图所示,建连的时序从上到下,左右两边的绿色分别代表Client和Server端当时的链接状态。
image.png
首先建立链接前需要Server端先监听端口,因此Server端建立链接前的初始状态是LISTEN状态,这是Client端准备建立链接,先发送一个SYN同步包,发送完同步包后,Client端的链接状态变成了SYN_SENT状态。Server端收到SYN后,同意建立链接,会向Client端回复一个ACK。
由于TCP是双向传输,Server端也会向Client端发送一个SYN,申请Server向Client方向建立链接,发送完SYN和ACK后,Server端就变成了SYN_RCVD。
Client收到Server的ACK后,Client状态就变成了ESTABLISHED,同时,Client向Server端发送ACK,回复Server端的SYN请求。
Server端收到Client端ACK后,Server端状态也变成ESTABLISHED状态,此时建连完成,双方随时可以进行数据传输。
如果面试的时候,我们需要明白三次握手为了建立双向链接,需要记住Client端和Server端的链接状态变化。另外回答建连的问题时,可以提到SYN洪水攻击发生的原因,就是Server端接收到Client端的SYN请求后,发送了SYN和ACK,但是Client端不进行回复,导致Server端大量的链接处在SYN_RCVD状态,进而影响其它正常请求建连。可以设置tcp_synack_retries = 0加快半链接的回收速度,或者调大tcp_max_syn_backlog来应对少量的SYN洪水攻击
2. 详解四次挥手断连
接下来看一看,TCP断连,如下图:
image.png
TCP链接的关闭,双方都可以先发起,我们暂时把先发起的一端称为Client端,,从图上可以看出,通信中的Client和Server都处于ESTABLISHED状态,然后Client先主动发起了关闭链接请求,Client向Server发送一个FIN包,表示Client端已经没有数据要发送了,然后Client进入了FIN_WAIT_1状态。
Server端收到FIN后,返回ACK,然后进入CLOSE_WAIT状态。此时Server属于半关闭状态,因为此时Client已经不会向Server发送数据了,但是Server端可能还有数据要向Client发送。
当Server发送完毕后,Server端会向Client端发送FIN,表示Server端也没有数据需要发送了,此时Server进入LAST_ACK状态,就等待Client应答就可以关闭链接了。
Client端收到Server端的FIN后,回复ACK,然后进入TIME_WAIT状态。TIME_WAIT状态下需要等待2倍的最大报文段生存时间,来保证链接可靠关闭,之后才会进入CLOSED关闭状态。而Server端接收到ACK后会直接进入CLOSED状态。
这里有一个面试的知识点,面试官可能在这里问为什么需要等待2倍的最大报文段生存时间之后再关闭链接,原因有两个:
- 保证TCP协议的全双工链接能够可靠关闭
- 保证这次连接的重复数据段在网络中消失,防止端口被重用是可能造成数据混淆。
从上面的交互流程上可以看出,无论是建连还是断连,都是需要两个方向上进行的,只不过建连时,Server端的SYN和ACK合并为一次发送了,断连时两个方向上数据发送停止时间可能不同,所以不能合并发送FIN和ACK,这就是建连需要三次握手,而断连需要四次挥手的原因了
另外回答断连的问题时,可以提到实际应用中可能遇到大量Socket处在TIME_WIT或者CLOSE_WAIT状态的问题。一般开启tcp_tw_reuse和tcp_tw_recycle能过加快TIME_WAIT的Sockets回收;而大量CLOSE_WAIT可能是被动关闭的一方存在代码bug,没有正确关闭链接导致的。
网友评论