为啥 TCP Server 接受连接后会立即发送 FIN?

Posted

技术标签:

【中文标题】为啥 TCP Server 接受连接后会立即发送 FIN?【英文标题】:Why will a TCP Server send a FIN immediately after accepting a connection?为什么 TCP Server 接受连接后会立即发送 FIN? 【发布时间】:2011-04-21 16:18:54 【问题描述】:

从 ethreal 数据包捕获中,我看到以下对我来说似乎很奇怪的行为:

Client --> Server  [SYN]
Server --> Client  [SYN, ACK]
Client --> Server  [ACK]
Server --> Client  [FIN, ACK]
Client --> Server  [ACK]
Client --> Server  [TCP Segment of a reassembled PDU] (I don't know what this means)
Server --> Client  [RST]

关于为什么会发生这种情况的任何想法?

另外,服务器端口是 6000。这会导致什么问题吗?

我的其他疑问:

    为什么会有 FIN、ACK?不应该只有FIN吗?该消息中的 ACK 是什么意思? 不应该有来自客户端的 FIN 吗?

编辑: 经过进一步分析,我发现如果文件描述符的数量超过了限制,那么服务器会发送一个 FIN。但是,在这种情况下,文件描述符似乎没有超过限制。还有哪些情况会发生这种情况?

【问题讨论】:

服务器是远程的还是本地的?是否有可能是滥用 ISP 插入虚假数据包? 服务器是远程的。如何查明是否有任何伪造的数据包被插入? @Jay 关于1.请看publib.boulder.ibm.com/infocenter/tpfhelp/current/… 【参考方案1】:

经过深入分析,发现问题原因如下:

当客户端尝试 TCP 连接时,即使服务器当前没有调用接受,连接也会通过。如果服务器调用了“侦听”功能,就会发生这种情况,并且它将继续接受连接,直到达到积压限制。

但是,如果应用程序进程超过了它可以使用的最大文件描述符的限制,那么当服务器调用accept时,它就会意识到没有文件描述符可以分配给socket,并且accept调用和TCP失败向另一端发送 FIN 的连接。

我只是想在这里发布这个发现。我仍然将接受的答案保留为哈比的答案。

感谢所有回答这个问题的人。

【讨论】:

【参考方案2】:

FIN 通常表示套接字上名为shutdown(..) 的另一端。

【讨论】:

你的意思是说,在这种情况下,对 'accept' 的调用肯定会成功返回? 是的。如果没有 accept(),您只会看到静默并最终超时。 好的,但是,accept 不可能发送 FIN 对吧?我的意思是如果出现一些错误情况,有可能吗? 我不知道,当然。 嗯?不,连接是在调用 accept() 之前建立的 - listen() 的 backlog 参数指定了可以处于此状态的连接数(已连接,但尚未调用 accept())。【参考方案3】:

我猜想inetd 或类似的守护进程正在接受连接,然后它会尝试forkexec 另一个程序来处理连接,并且fork 失败(由于资源耗尽)或exec 失败(由于文件不存在、权限错误等)。

【讨论】:

【参考方案4】:

可能是TCP wrappers。如果服务器进程是使用 libwrap 支持构建的,它将接受连接,检查/etc/hosts.allow/etc/hosts.deny,如果被策略拒绝,则立即关闭连接。

很容易看出服务器是否在使用 libwrap:

> ldd /usr/sbin/sshd | grep libwrap
libwrap.so.0 => /lib64/libwrap.so.0 (0x00007f1562d44000)

【讨论】:

【参考方案5】:

我认为 FIN 是通过调用 close() 而不是 shutdown() 发送的。

连接在积压队列中;在 accept() 之后,服务器决定以任何原因终止它(例如 TCP 包装 ACL 或文件描述符不足)。在这种情况下,close() 将文件描述符 (FD) 的链接计数从 1 减少到 0,因此该连接的 FD 被完全销毁。之后,从服务器的角度来看,客户端将数据发送到一个不存在的套接字,服务器必须响应一个 RST。

如果是shutdown(),服务器仍然可以恢复客户端发送的数据,并且必须等待客户端的FIN才能优雅地关闭连接。没有 RST 被发回。

附言 close() vs shutdown()

【讨论】:

【参考方案6】:

似乎服务器在接受连接后不久就调用了shutdown

【讨论】:

以上是关于为啥 TCP Server 接受连接后会立即发送 FIN?的主要内容,如果未能解决你的问题,请参考以下文章

(经典)TCP粘包分析

什么是tcp长连接和短连接。谢谢

tcp三次握手 以及四次挥手

畅谈linux下TCP(上)

TCP的三次握手

服务端进程被杀掉,tcp连接处于FIN_WAIT2状态,为啥客户端调用socket发送数据还是成功的。