我试图在连接上强制重置 TCP。 建议的方法是将 SO_LINGER 设置为 0 并调用 close()。
我正在这样做,但连接仍处于 ESTABLISHED 状态。 套接字以非阻塞模式运行。操作系统是 Raspbian。
代码:
struct linger l;
l.l_onoff = 1;
l.l_linger = 0;
if (setsockopt(server->connection_socket, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) != 0) {
LOG_E(tcp, "setting SO_LINGER failed");
}
if (close(server->connection_socket) != 0) {
LOG_E(tcp, "closing socket failed");
}
server->connection_socket = 0;
LOG_I(tcp, "current TCP connection was closed");
Wireshark 跟踪也显示没有 RST。
应用程序的其他线程没有在该套接字上执行任何操作。
我不知道哪里出了问题,任何建议将不胜感激。
已解决
问题是文件描述符泄漏给通过 system()
调用创建的子项。
事实上,当我使用 lsof -i tcp
列出所有 TCP 套接字描述符时,我发现子进程已经从父进程打开了文件描述符(即使父进程已经没有)。
解决方案是请求在 fork 进程中关闭文件描述符(紧接在 accept()
之后)。
fcntl(server->connection_socket, F_SETFD, FD_CLOEXEC)
最佳答案
在您的情况下,您在调用 close
后无法再发送和接收数据。此外,在 close
调用之后,仅当套接字描述符的引用计数器变为 0 时才会发送 RST。然后连接进入 CLOSED
状态,并且数据在接收和发送中缓冲区被丢弃。
答案可能在于你如何 fork 一个过程(正如 EJP 在评论中提到的那样)。您似乎在调用fork
后没有关闭父进程中已接受的套接字。所以套接字引用计数器不为零,并且在您的关闭
之后没有立即执行 RST。
Stevens 在 UNIX 网络编程中很好地描述了这种情况。
关于带有 SO_LINGER 的 close() 不会发送 RST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41023657/