【问题标题】:bind() with SO_REUSEADDR fails带有 SO_REUSEADDR 的 bind() 失败
【发布时间】:2011-11-30 18:13:39
【问题描述】:

我的任务是实现在通过 TCP 连接的两台计算机之间进行的两人游戏。其中一项要求是只有获胜者才能选择是否再次游戏。如果服务器获胜并决定不再继续游戏,客户端应作为服务器重新启动并接受新连接。

我的方法: 如果游戏丢失(在客户端模式下),关闭 sockfd 并重新创建另一个。然后使用 setsockopt 允许使用 SO_REUSEADDR 重新绑定,然后调用 bind。

int yes = 1;
if ( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 )
{
    perror("setsockopt");
}

if ( bind(sockfd, (struct sockaddr*)&svr, sizeof(svr) ) == -1 )
{
    perror("server: bind");
}

但是,我仍然收到相同的“地址已在使用”错误。在重新创建套接字之前,我尝试睡了 150 秒,并且此方法有效。

注意:我正在同一台 PC 上进行测试。它可以在两台链接的 PC 上运行,但必须让它在同一台 PC 上运行。请帮忙。

【问题讨论】:

  • 请出示您的代码(尤其是setsockopt() 周围的部分)以便我们提供帮助。
  • 您确定在客户端代码中尝试重新创建服务器端(侦听套接字)之前已正确关闭它吗?在 Linux 系统上,“netstat -tlp”应该确定是什么让 TCP 端口处于打开状态以监听它...
  • 您尝试在一台机器上绑定()相同的 {address,portnum} 两次?您希望会发生什么?
  • 好吧,等待 120 秒后,该方法有效。所以我想它可以通过使用 SO_REUSEADDR 立即工作。但是,如果我错了,请告诉我。
  • @BRPocock:你是对的。在套接字关闭之前有一个 sleep(1),这就是我无法绑定的原因。现在,它完美运行。感谢您的提示! :)

标签: c sockets bind


【解决方案1】:

SO_REUSEADDR 只允许您同时绑定到一个更具体的地址,即第一个服务器侦听INADDR_ANY(所有接口),随后的服务器侦听不同的具体接口地址。 p>

第二种情况是当侦听 TCP 套接字接受一个连接时,该连接一直在使用,但侦听套接字本身已关闭然后重新打开 - 比如说父服务器进程退出并重新启动。

在这两种情况下,您都需要在调用bind(2) 之前始终在侦听套接字上设置SO_REUSEADDR 选项。

【讨论】:

  • 那么..还有其他方法吗?我在两次调用之前都使用了 SO_REUSEADDR。
  • 当刚刚关闭的套接字处于 TIME_WAIT 状态时,此选项通常用于在重新启动侦听特定端口的服务器时避免等待 1-2 分钟。
【解决方案2】:

由于您在同一系统上运行此程序,因此听起来您遇到了竞争条件。客户端在服务器关闭套接字之前尝试bind()(假设服务器和客户端都在它们的套接字上设置SO_REUSEADDR)。

您需要实现某种握手,让服务器在关闭侦听套接字后通知客户端 - 也许服务器应该在关闭上一场比赛的活动套接字之前关闭侦听套接字?

【讨论】:

  • 是的,在套接字关闭之前有 1 秒的延迟,当我尝试重新绑定它时没有延迟。它现在工作得很好! :)
【解决方案3】:

设置此套接字选项允许本地地址重用。如果在尝试绑定到已关闭但未释放的端口时遇到问题(可能需要长达 2 分钟,由 TIME_WAIT 定义)。应用 SO_REUSEADDR 套接字选项以立即释放资源并绕过 TIME_WAIT 状态。 0 = 禁用,1 = 启用。

允许其他套接字绑定()到这个端口,除非已经有一个活动的监听套接字绑定到该端口。这使您能够在崩溃后尝试重新启动服务器时绕过那些“地址已在使用”错误消息

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-31
    • 2020-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-14
    • 2017-04-21
    相关资源
    最近更新 更多