【问题标题】:Socket keepalive not working套接字保持活动不工作
【发布时间】:2014-03-19 00:43:15
【问题描述】:

我有一个连接到服务器的客户端 connect(),当空闲时,它会在几个小时后超时。 我添加了 setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE...) 1 秒 但这并没有什么不同。 关于keepalive为什么不起作用的任何线索? 如果我使用 SOL_TCP 而不是 SOL_SOCKET 会有所不同吗? 这是在 Linux 上。

【问题讨论】:

  • 定义“几个小时后超时”。那具体的症状是什么?
  • errno 110 - 连接超时。我做了一个 tcpdump 并没有看到 keepalive 消息
  • 设置 TCP_USER_TIMEOUT 选项可能会解决问题。

标签: c++ linux sockets tcp


【解决方案1】:

尽管它的名字,keep-alive 不是保持连接活动,它是关于定期交换数据包以确保对等点之间存在网络路径。它会在空闲时终止可以在长时间网络中断中幸存下来的连接。

由于这种行为,除非有充分的理由,否则不应使用 keep-alive,例如 telnet 或 SSH 连接,在客户端失去联系时终止会话是合理的。

由于某些连接处理策略,很可能是服务器在 n 小时后关闭连接,无论是否使用 keepalive。

【讨论】:

  • 没有。服务器没有关闭它。连接仅在空闲时超时。 keepalive 的目的是让它看起来“非空闲”——那是没有用的
  • 可能是某些中间路由器/防火墙/NAT 建立了连接超时。在 Linux 中,常见的 NAT 超时为 1 小时(3600 秒)。
  • 当像防火墙/NAT这样的网络中介决定终止一个空闲连接时,它会(在大多数情况下)简单地消除它而不通知连接的对等方连接已经消失(没有FIN数据包, 例如)。结果,从对等点的角度来看,连接是活动的,他们可以发现套接字已经消失的唯一方法是使用读取超时。使用 keepalive 机制,TCP/IP 堆栈会检测到断开连接,因此应用程序会更早地收到断开连接的通知(如果适当降低空闲时间设置)。
【解决方案2】:
int val = 1;
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof val)

只启用keepalives。您将获得 keepalive 探测的默认计时器,您可以使用以下命令查看:

sysctl net.ipv4.tcp_keepalive_time

通常默认为几个小时。

如果你想改变默认定时器,你可以使用这个:

struct KeepConfig cfg = { 60, 5, 5};
set_tcp_keepalive_cfg(fd, &cfg);

这里有辅助函数:

struct KeepConfig {
    /** The time (in seconds) the connection needs to remain 
     * idle before TCP starts sending keepalive probes (TCP_KEEPIDLE socket option)
     */
    int keepidle;
    /** The maximum number of keepalive probes TCP should 
     * send before dropping the connection. (TCP_KEEPCNT socket option)
     */
    int keepcnt;

    /** The time (in seconds) between individual keepalive probes.
     *  (TCP_KEEPINTVL socket option)
     */
    int keepintvl;
};

/**
* enable TCP keepalive on the socket
* @param fd file descriptor
* @return 0 on success -1 on failure
*/
int set_tcp_keepalive(int sockfd)
{
    int optval = 1;

    return setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
}

/** Set the keepalive options on the socket
* This also enables TCP keepalive on the socket
*
* @param fd file descriptor
* @param fd file descriptor
* @return 0 on success -1 on failure
*/
int set_tcp_keepalive_cfg(int sockfd, const struct KeepConfig *cfg)
{
    int rc;

    //first turn on keepalive
    rc = set_tcp_keepalive(sockfd);
    if (rc != 0) {
        return rc;
    }

    //set the keepalive options
    rc = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &cfg->keepcnt, sizeof cfg->keepcnt);
    if (rc != 0) {
        return rc;
    }

    rc = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &cfg->keepidle, sizeof cfg->keepidle);
    if (rc != 0) {
        return rc;
    }

    rc = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &cfg->keepintvl, sizeof cfg->keepintvl);
    if (rc != 0) {
        return rc;
    }

    return 0;
}

【讨论】:

  • 这就是我想要的。谢谢
  • 非常感谢。它拯救了我的一天。像应用程序这样的“聊天”是否有任何规定的超时时间?如果您在内部描述这些方法的作用,会有所帮助吗?他们是否向服务器套接字发送 0 个有效负载数据包?这是昂贵的操作吗(例如,可能是创建了一个新线程)?顺便说一句,@excalibur,如果您满意,您应该点击投票下方的右勾号来接受此答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-03
  • 2010-09-23
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-20
相关资源
最近更新 更多