Почему может рваться TCP-подключение без видимых причин?
Сервер (TcpListener) слушает клиента (бесконечный цикл, в потоке).
Единственный клиент (TcpClient) слушает сервер (бесконечный цикл, в потоке).
Оба цикла висят на вызове Read(), так как ни сервер ничего не пишет клиенту, ни клиент - серверу.
Оба приложения консольные. Больше ничего не выполняется.
Сервер находится на VPS, клиенты разные были, от этого ничего не меняется.
Проблема, собственно, в том, что спустя так полчаса простоя, у сервера Read вдруг вылетает в Exception, обычно так бывает если клиент рвет подключение.
Такое бывает если убить процесс клиента, но он цел.
Думал, что дело может быть в кратковременном пропадании подключения к интернету. На клиенте отключался от сети, затем подключался. Ничего подобного - все работает.
Какие еще версии?
Сам Exception пока не смотрел, не было возможности, я по глупости сделал try catch который его "проглатывал" и выводил только сухое сообщение в лог. На локалхосте пока не пробовал. Все это я буду делать, но надеюсь что вы поможете.
Vermut756: Особой разницы нет, можно включить и там и там. На сервере это позволит быстрее освобождать ресурсы при обрыве, ну а клиент просто раньше поймёт, что нет связи с сервером и сможет переустановить соединение.
Rsa97: А вот еще есть такой параметр в реестре HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\KeepAliveTime
Вернее, по умолчанию его там нет, в статье пишут что в таком случае он равен 2 часам. Какое именно время он задает? Это и есть то время, когда соединение рвется если НЕ установлена опция KeepAlive?
Rsa97: А вот еще есть такой параметр в реестре HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\
KeepAliveTime
Вернее, по умолчанию его там нет, в статье пишут что в таком случае он равен 2 часам. Какое именно время он задает? Это и есть то время, когда соединение рвется если НЕ установлена опция KeepAlive?
Написано только что
Vermut756: Нет. Если включена опция KeepAlive, то через каждые KeepAliveTime миллисекунд в TCP-канал с интервалом KeepAliveInterval посылается не более MaxDataRetries контрольных пакетов до получения ответа. Если ответа не было, то канал обрывается.
Саму опцию KeepAlive на сокете включает прикладная программа, а обрабатывается она уже системой.
Время можно поменять в параметрах сокета, например так: http://stackoverflow.com/questions/169170/what-is-...
Vermut756: Обычно делают 1-5 минут, чтобы не терялись записи в таблице NAT на маршрутизаторах. Чем меньше время, тем быстрее станет известно об обрыве, но больше вероятность, что при кратковременном (несколько секунд) перебое связи канал оборвётся.
Rsa97: "Обычно" очень напрягает... Может втопку keepalive и просто сделать на клиенте таймер, который будет выявлять дисконнект и тут же переподключаться?
Не зря же в некоторых программах типа мессенджеров была опци "поддерживать соединение" которая периодически отправляла не значащие в рамках протокола пакеты.
Upd https://habrahabr.ru/company/intersystems/blog/155565/
Проблема может быть в том, что между клиентом и сервером NAT и на роутере из-за неактивности "протухает" запись в таблице NAT. Но решение, которое подсказали выше (keep-alive) поможет и в данном случае, только помимо собственно keep-alive'а необходимо установить keep-alive timeout секунд в 300 хотя бы, т.к. дефолтное значение (обычно 7200 секунд) вас не спасет. Т.е. помимо SO_KEEPALIVE необходимо установить TCP_KEEPIDLE/SIO_KEEPALIVE_VALS в зависимости от системы. В качестве альтернативы вы можете предусмотреть отправку keep-alive пакетов на уровне прикладного протокола. Обычно протоколы, рассчитанные на длинные соединения с небольшим трафиком, например мессенджеры, используют именно протокольные keep-alive.
Владимир Дубровин: А как узнать, как часто отправлять контрольные пакеты? Или как задать в системе (сервер или клиент), чтобы за такой-то интервал без контрольных пакетов соединение не рвалось?
Vermut756: возьмите разумный интервал, обычно берут 5 минут (300 секунд). В системе можно задать keep-alive'ы для всех соединений, как - зависит от системы, поищите по TCP keep-alive с названием системы.
соответственно, если даже сервер, например, узнает что коннект разорван, когда попытается отправить данные клиенту и будет считать,Ю что соединение завершено - клиент может продолжать висеть и считать что коннект в порядке, пока сам что-то записать не попытается. Т.е. надо в любом случае делать кипэлайв на уровне приложения, если не хотите делать на уровне TCP.