带有 SO_LINGER 的 close() 不会发送 RST

标签 c linux sockets tcp

我试图在连接上强制重置 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/

相关文章:

c++ - Visual Studio 令人困惑的异常

linux - UDP 数据包丢弃 - INErrors 与 .RcvbufErrors

linux - 在 Apache httpd 和模块中搜索内存泄漏

php - 为什么 TCP 工作,而 UDP 不工作?

c - 如何计算C中的 float ?

c - C 语言中 long 类型转换为 int 类型以及 Short 类型

c - 在 pebble watch 上记录枚举

linux - 在 Mathematica 中运行 ssh 命令

C# 套接字 : Do I really need so many separate threads

windows - 微软加密 API 书