又被鹅厂搞懵了!
时间:2021-09-03 10:13:03
手机看文章
扫描二维码
随时随地手机看文章
[导读]大家好,我是小林。昨天收到个读者的问题,他在面试鹅厂的时候,被面试官搞懵了,因为面试官问了他这么一个网络问题:不得不说,鹅厂真的很喜欢问网络问题,而且爱问异常情况下的网络问题,之前也有篇另外一个读者面试鹅厂的网络问题:「被鹅厂面怕了!」。我们来看看这位读者的问题,这个问题其实是在...
大家好,我是小林。昨天收到个读者的问题,他在面试鹅厂的时候,被面试官搞懵了,因为面试官问了他这么一个网络问题:不得不说,鹅厂真的很喜欢问网络问题,而且爱问异常情况下的网络问题,之前也有篇另外一个读者面试鹅厂的网络问题:「被鹅厂面怕了!」。我们来看看这位读者的问题,这个问题其实是在问:客户端(主动关闭方)在 TIME_WAIT 状态下,如果收到服务端的数据包时,会怎么处理?这个问题迷惑性在于,客户端是使用了 shutdown 函数关闭了写方向,而读方向并没有关闭,也就是说客户端在挥手过程中,如果收到服务端的数据包,那么应用程序在调用 read 函数时,是可以读取到数据的。如果问题中的数据包没有被网络延迟,在第三次挥手之前被客户端收到了,那么客户端就可以在应用程序读取到该数据。所以疑惑就在于,数据包被延迟了,客户端在进入 TIME_WAIT 状态后,收到了服务端的数据包,应用程序还能读取到该数据吗?我先说结论吧,客户端进入 TIME_WAIT 状态后,如果收到了服务端的数据包,客户端的内核会发送该数据包的 ACK 确认报文,然后丢掉该数据包。
我为什么知道呢?因为我去看了下内核的源码,我在这里也带大家分析一遍。Linux 内核在收到 TCP 报文后,会执行
「别再摸鱼了,再摸鱼,我就吃了你!」
我为什么知道呢?因为我去看了下内核的源码,我在这里也带大家分析一遍。Linux 内核在收到 TCP 报文后,会执行
tcp_v4_rcv
函数,在该函数和 TIME_WAIT 状态相关的主要代码如下所示:该代码的过程:- 接收到SKb包后,会调用__inet_lookup_skb()查找对应的sock结构;
- 如果连接的状态是 TIME_WAIT,会跳转到 do_time_wait 处理;
- 由 tcp_timewait_state_process() 函数来处理 SKB 包,处理后根据返回值来做相应的处理。
- 如果返回值是 TCP_TW_SYN,则说明接收到的是一个「合法」的SYN包(也就是说这个 SYN 包可以接受),这时会首先查找内核中是否有对应的监听套接字,如果存在相应的监听套接字,则会释放TIME_WAIT状态的传输控制结构,跳转到 process 处开始处理,开始建立一个新的连接。如果没有找到监听套接字会执行到 TCP_TW_ACK 分支。
- 如果返回值是TCP_TW_ACK,则会调用 tcp_v4_timewait_ack() 发送ACK,然后跳转到 discard_it,丢掉数据包。
- 如果返回值是TCP_TW_RST,则会调用 tcp_v4_send_reset() 给对端发送 RST 包,然后丢掉数据包。
- 如果返回值是TCP_TW_SUCCESS,则会直接丢掉数据包。
「别再摸鱼了,再摸鱼,我就吃了你!」