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

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

本文关键字:错误 setsockopt 选项 超时 使用      更新时间:2023-10-16

现在,我正尝试使用以下代码用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()电话时,一切都很好。然而,添加了第二个(不返回任何错误)后,我遇到了代码中指定的第二个"侦听错误"。我不知道为什么设置超时值会影响这一点,有人能解释一下吗?

我不相信指定的代码;它是从教程中提供的代码修改而来的:http://codebase.eu/tutorial/linux-socket-programming-c/

如果您看到像这样的TCP状态图,您会看到在主动关闭套接字时有一个名为TIME_WAIT的状态。这种状态可能需要一些时间才能结束,根据RFC793,最长需要四分钟。

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

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


至于您的问题,在每次调用setsockopt之后,请检查它返回的内容,如果是-1,则检查errno以查看出了什么问题。您可以使用perrorstrerror打印或获取错误的可打印字符串,如

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()。为了回答我自己的问题,在意识到代码中的问题更深入之后,超时会影响服务器侦听端口的能力。假设超时只有10ms,必须启动服务器,然后启动客户端,并且必须在这段时间内建立连接。在我的案例中没有发生这种情况,因此产生了错误。