TCP四次挥手,如果客户端进入了FIN-WAIT-2状态,又想向服务端发送消息了,会发生什么情况?
原创
车小胖谈网络
车小胖谈网络
车小胖谈网络
2026年7月26日 13:33
上海
在小说阅读器读本章
去阅读
What happens if the client is in the FIN-WAIT-2 state and wants to send a new message to the server?
能让客户端的TCP进入FIN-WAIT-2状态的,客户端一般调用2种syscall:
- close(fd)
- shutdown(fd, SHUT\_WR) 或者 shutdown(fd, SHUT\_RDWR)
其中fd= file descriptor。
假设调用syscall函数 socket成功返回fd=10,再调用connect(fd,…) = connect(10,…),经过3次握手,成功建立tcp连接,状态为established。
内核是如何从客户端进程的视角追踪这个状态的?
p->files->fdt->fd[10]->private\_data->sk->sk\_state == established
其中,p客户端进程task\_struct实例的指针。如果不好理解,可以理解为客户端进程task\_struct实例的base address。
加亮的10代表fd inex,代表在fd[] array里的index。
如果客户端再建立一个TCP连接,假如分配的fd =11,那么跟踪它的状态就可以用:
p->files->fdt->fd[11]->private\_data->sk->sk\_state == established
如果客户端没有打开更多的文件,或者创建更多的tcp连接。那么
p->files->fdt->fd[12] == NULL ==0
p->files->fdt->fd[13] == NULL ==0
。。。
场景1:客户端调用shutdown(10, SHUT\_WR)
内核用fd=10作为index来填入p->files->fdt->fd[]这个数组,并判断
p->files->fdt->fd[index] == p->files->fdt->fd[10] 是否== NULL?
如果NULL,说明fd 10对应的内核struct完全释放或者不存在,比如fd 12,13要么曾经使用过但是已经被释放内存,或者压根没有存在过。
如果不是NULL,继续check:
p->files->fdt->fd[10]->private\_data== NULL?
如果不是NULL,继续check
p->files->fdt->fd[10]->private\_data->sk == NULL?
如果不是NULL,继续check当前的状态:
p->files->fdt->fd[10]->private\_data->sk->sk\_state == established?
我们拥有上帝的视角,知道 fd=10代表的tcp连接状态为established状态。
但是,CPU不具有上帝视角,做每一个de-reference操作之前,都确保不是NULL地址,或者内存地址0,否则系统会崩溃。以上每一步check如果是NULL,syscall直接返回用户栈,并把errer code返回。
由于以上每一步都成功了,tcp发现该TCP连接状态是established,用户想发送End of File == EOF== FIN,可以吗?
当然可以了,于是TCP发出了FIN报文,并更新状态为:
p->files->fdt->fd[10]->private\_data->sk->sk\_state = fin\_wait\_1
收到服务器对自己FIN消息的ACK报文之后,客户端tcp更新状态为:
p->files->fdt->fd[10]->private\_data->sk->sk\_state = fin\_wait\_2
题主的问题来了,此情此景,客户端能用send(10,…)发送新的数据吗?
send是465种syscall的一种类型,客户端可以自由调用自己喜欢的syscall。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论