使用 setsockopt() 指定超时选项会导致随后的侦听错误

Specifying timeout option with setsockopt() results in subsequent listen error

现在,我正在尝试使用以下代码通过 setsockopt() 指定选项:

// bind socket
// Use setsockopt() function to make sure the port is not in use
int yes = 1;
setsockopt(TCPSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
setsockopt(TCPSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
status = bind(TCPSocket, host_info_list->ai_addr, host_info_list->ai_addrlen);
if (status == -1)  std::cout << "bind error" << std::endl ;

// listen for connections
status =  listen(TCPSocket, 5);
if (status == -1)  std::cout << "listen error" << std::endl ;

int new_sd;
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
new_sd = accept(TCPSocket, (struct sockaddr *)&their_addr, &addr_size);
if (new_sd == -1) std::cout << "listen error" << std::endl ;

注意tv是一个已经指定的时间间隔。

当我只进行第一个 setsockopt() 调用时,一切正常。但是,加上第二个(没有 return 任何错误),我遇到了代码中指定的第二个 "listen error"。我不确定为什么设置超时值会影响这一点,有人可以解释一下吗?

我不认为指定的代码是我的功劳;它是根据此处教程中提供的代码修改的:http://codebase.eu/tutorial/linux-socket-programming-c/

如果您看到 TCP 状态图 like this one you see there's a state called TIME_WAIT when actively closing a socket. This state can take some time before it ends, up to four minutes according to RFC793

当套接字处于 TIME_WAIT 时,您不能使用与处于等待状态的套接字相同的地址-端口对绑定到接口。在套接字上设置 SO_REUSEADDR 标志可以让其他套接字在当前套接字(设置了标志)处于 TIME_WAIT 状态时绑定到该地址。

SO_REUSEADDR 选项对服务器(被动、侦听)套接字最有用。


至于你的问题,每次调用 setsockopt check what it returns, and if it's -1 then you check errno to see what went wrong. You can use perror or strerror 打印或获取错误的可打印字符串后,如

if (setsockopt(TCPSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0)
{
    std::cerr << "Error setting the SO_REUSEADDR: " << strerror(errno) << '\n';
    // Do something appropriate
}

Joachim 的解决方案很好地回答了我最初的问题并解释了 setsockopt()。在意识到问题在代码的更下方之后回答我自己的问题,超时会影响服务器能够侦听端口。假设超时只有 10 毫秒,必须启动服务器,然后是客户端,并且必须在那个时间内建立连接。这在我的案例中没有发生,因此导致了错误。