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

时间:2015-11-23 06:49:25

标签: c++ linux setsockopt

现在,我正在尝试使用以下代码指定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/

2 个答案:

答案 0 :(得分:2)

如果您看到TCP状态图like this one,则在主动关闭套接字时会看到名为TIME_WAIT的状态。根据{{​​3}},此状态可能需要一段时间才能结束,最多可达四分钟。

当套接字在TIME_WAIT中时,您无法使用与处于等待状态的套接字相同的地址 - 端口对绑定到接口。将套接字SO_REUSEADDR设置为允许其他套接字在当前套接字(设置了标志)处于TIME_WAIT状态时绑定到该地址。

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

关于您的问题,在每次致电RFC793后检查它返回的内容,如果是-1,那么请检查setsockopt以查看出现了什么问题。您可以使用errnoperror打印或获取错误的可打印字符串,例如

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

答案 1 :(得分:0)

Joachim的解决方案很好地回答了我的初始问题并解释了setsockopt()。在意识到问题进一步发生在代码中之后回答我自己的问题时,超时会影响服务器能够监听端口。假设超时仅为10毫秒,必须启动服务器,然后是客户端,并且必须在此时建立连接。在我的情况下没有发生这种情况,从而导致错误。