2014-02-18 6 views
5

У меня есть клиент connect() на сервере, а при простоя он истекает через пару часов. Я добавил setsockopt (socket, SOL_SOCKET, SO_KEEPALIVE ...) с 1 сек. , но это не помогло. Любые подсказки о том, почему keepalive не работает? Будет ли это иметь значение, если я использовал SOL_TCP вместо SOL_SOCKET? Это на Linux.Socket keepalive не работает

+0

Определить время после нескольких часов. Какой именно симптом этого? – EJP

+0

errno 110 - Время ожидания подключения. Я сделал tcpdump и не вижу сообщений keepalive. – excalibur

ответ

7
int val = 1; 
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof val) 

Просто позволяет keepalives. Вы получите таймеры по умолчанию для поддержки активности зондов, которые можно просмотреть с помощью команды:

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

+0

Большое спасибо. Это спасло мой день. Есть ли установленный тайм-аут для «чата», например, приложения? Будет полезно, если вы опишете, что эти методы делают внутри? Они отправляют 0 пакетов полезной нагрузки на серверный сокет? Это дорогостоящая операция (например, может быть создан новый поток)? BTW, @excalibur, вы должны принять этот ответ, нажав правую отметку ниже голосов, если вы удовлетворены. – iammilind

2

Несмотря на свое название, поддержание активности не о сохранении связи живой, речь идет об обмене пакетов периодически, чтобы убедиться, что существует сетевой путь между одноранговыми узлами. Он убивает соединения, которые будут выдерживать продолжительные отключения сети в режиме ожидания.

В связи с этим поведение keep-alive не должно использоваться, если нет веских причин, таких как telnet или SSH-соединения, где разумно убивать сеанс, когда клиент выходит из прикосновения.

Скорее всего, это сервер, который закрывает соединение через n часов независимо от использования keepalive из-за некоторой политики обработки соединений.

+0

№ Сервер не закрывает его. Соединение отключается только при его простоях. Цель keepalive состоит в том, чтобы заставить его казаться «не праздным» - и это то, что не работает – excalibur

+0

Возможно, какой-то промежуточный маршрутизатор/брандмауэр/NAT установил таймаут соединения. В Linux общий тайм-аут NAT составлял 1 час (3600 секунд). – epx

+0

Когда сетевой посредник, такой как брандмауэр/NAT, решает убить незанятое соединение, он (в большинстве случаев) просто устранит его, не уведомив соединительные одноранговые узлы о том, что соединение прошло (например, пакет FIN). В результате, с точки зрения сверстников, соединения живы, и единственный способ узнать, что сокет ушел, - использовать тайм-аут чтения. С помощью механизма keepalive стек TCP/IP обнаруживает разъединение, и поэтому приложение будет уведомлено об отключении намного раньше (если настройки времени простоя будут соответственно опущены). –

Смежные вопросы