使用SO_LINGER的close()不会发送RST

时间:2016-12-07 17:24:34

标签: 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套接字描述符时,我发现子进程已经从父进程打开了文件描述符(即使父进程已经没有)。

解决方案是请求在分叉进程中关闭文件描述符(在accept()之后)。

fcntl(server->connection_socket, F_SETFD, FD_CLOEXEC)

1 个答案:

答案 0 :(得分:1)

在您调用close后,您无法再发送和接收数据。此外,在close调用之后,仅当套接字描述符的引用计数器变为0时才会发送RST。然后连接进入CLOSED状态,并且丢弃接收和发送缓冲区中的数据。 /> 可能答案在于你如何分叉一个过程(正如EJP在评论中提到的那样)。在调用fork之后,您似乎没有在父进程中关闭已接受的套接字。因此套接字引用计数器非零,并且在close之后没有RST 史蒂文斯在UNIX网络编程中很好地描述了这种情况。