LINUX.ORG.RU

TCP. Как сделать надёжное соединение?

 


2

1

Если связь нестабильна, то tcp соединения часто уходят в какую-то «спячку». При этом второе соединение к тому же серверу успешно открывается, то есть связь есть. Есть возможность в своём клиент-серверном приложении придумать какое-то нормальное решение?

Необходимо оперативно получать оповещение с удалённого компьютера (когда событие произошло, оповещение надо через пару секунд), а получатель оповещения за NAT'ом. Пока придумал только постоянно гонять сообщения, что всё хорошо, а если больше, чем на секунду задержка, то сбрасывать соединение и соединяться заново. Но выглядит как-то костыльно. Кажется, что тогда проще на UDP накостылять свой надёжный протокол.

Есть какие-нибудь идеи?

★★★★★

Крутить таймауты TCP - они ЕМНИП там растут нелинейно при потерях пакетов и обрывах. Но могу что-то путать.

Pinkbyte ★★★★★ ()
Ответ на: комментарий от Pinkbyte

Крутить таймауты TCP

В операционке? И на клиенте и на сервере? А в приложении как-нибудь можно сделать?

monk ★★★★★ ()

Но выглядит как-то костыльно. Кажется, что тогда проще на UDP накостылять свой надёжный протокол.

У TCP есть параметр окно, попробуй уменьшить окно, тогда отзывчивость будет выше.

связь нестабильна, то tcp соединения часто уходят в какую-то «спячку». При этом второе соединение к тому же серверу успешно открывается, то есть связь есть. Есть возможность в своём клиент-серверном приложении придумать какое-то нормальное решение?

Сделай через UDP контрольный поток. По которому стороны сообщают какие данные были посланы по TCP. Тогда программа будет показывать пользователю в строке состояния индикатор задержки потока.

rezedent12 ☆☆☆ ()
Ответ на: комментарий от rezedent12

тогда отзывчивость будет выше

Из-за размеров окна соединение (например, SSH) может залипать на несколько минут? Причём в netstat размер очереди Send-Q растёт, состояние соединения ESTABLISHED, но к получателю по этому соединению пакеты не попадают.

Сделай через UDP контрольный поток.

Если обрыв связи, то в UDP часть данных потеряется. После этого UDP проснётся, TCP повиснет. Но вытащить данные из повисшего потока всё равно не получится, а если в UDP потеряется как раз нужное оповещение, то будет очень неприятно. Можно сделать на UDP встречный поток подтверждений и номера сообщений, но это уже будет TCP на коленке.

monk ★★★★★ ()
Ответ на: комментарий от beastie

Покури ещё тут: http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/

Спасибо. Это уже лучше. Значит можно вместо данных гонять пустые TCP пакеты.

Ещё бы найти способ TCP соединение реанимировать, а не прибивать и тут же делать новое туда же.

monk ★★★★★ ()
Ответ на: комментарий от monk

Если сессия оборвалась, то её уже AFAIK не реанимируешь. Но keepalive может позволить ловить такое событие раньше.

beastie ★★★★★ ()
Ответ на: комментарий от beastie

Если сессия оборвалась, то её уже AFAIK не реанимируешь.

Она не оборвалась. Вот, например, ssh. В netstat висит. Пишет ESTABLISHED. На клиенте в Send-Q неотправленные пакеты. На сервере тоже ESTABLISHED. Висеть так может пару минут. Дальше иногда отвисает, иногда налетает на таймаут.

При этом пинг идёт. Можно поднять второй ssh, посмотреть на это соединение с двух сторон (так и вижу, что на обоих концах ESTABLISHED).

monk ★★★★★ ()
Ответ на: комментарий от monk

Из-за размеров окна соединение (например, SSH) может залипать на несколько минут?

Не может. Размер окна - это количество пакетов, которые могут передаваться без подтверждения приёма. Окно настраивается автоматически, в зависимости от надежности канала. Если получатель постоянно запрашивает повторную отправку - окно уменьшается, если все пакеты идут без проблем - увеличивается.

Хотел кинуть ссылку на tcp-keepalive-howto, но бисти уже всё сделал.

CaveRat ★★ ()
Ответ на: комментарий от monk

Ещё бы найти способ TCP соединение реанимировать, а не прибивать и тут же делать новое туда же.

Похоже что какая-то промежуточная железка, вроде файрвола или слишком умного коммутатора, теряет состояние для соединения из-за чего его начинает перманентно блочить...

... а получатель оповещения за NAT'ом.

ну или NAT это делает. Просто так навряд ли сможешь реанимировать соединение.

mashina ★★★★★ ()
Ответ на: комментарий от mashina

Похоже что какая-то промежуточная железка, вроде файрвола или слишком умного коммутатора, теряет состояние для соединения из-за чего его начинает перманентно блочить...

Железяки от cisco любят молча обрывать соединения, если они простаивают, и делают это обычно без какого-либо уведомления. Поэтому keep-alive, а как он будет реализован, на уровне системы или приложения, дело уже десятое.

dave ★★★★★ ()
Ответ на: комментарий от mashina

Просто так навряд ли сможешь реанимировать соединение.

Ясно. А не слышал про какую-нибудь библиотеку, чтобы она пересоединение сама делала? Может zmq или что-то ещё так умеет?

monk ★★★★★ ()
Ответ на: комментарий от monk

Из-за размеров окна соединение (например, SSH) может залипать на несколько минут?

Не манипулировал размером окна ssh соединения на нестабильных каналах.

rezedent12 ☆☆☆ ()
Ответ на: комментарий от monk

Если обрыв связи, то в UDP часть данных потеряется. После этого UDP проснётся, TCP повиснет. Но вытащить данные из повисшего потока всё равно не получится, а если в UDP потеряется как раз нужное оповещение, то будет очень неприятно. Можно сделать на UDP встречный поток подтверждений и номера сообщений, но это уже будет TCP на коленке.

Что мешает сделать автоматическое переподключение если UDP мониторинг обнаруживает разрыв канала?

rezedent12 ☆☆☆ ()
Ответ на: комментарий от rezedent12

сделать автоматическое переподключение если UDP мониторинг обнаруживает разрыв канала

Тогда tcp_keepalive на порядок проще.

monk ★★★★★ ()
Ответ на: комментарий от monk

Тогда tcp_keepalive на порядок проще.

насколько я понял tcp_keepalive «живет» в ядре и в своей программе никак не узнать о событиях keepalive или что сейчас с соединением, кроме как что оно оборвалось через какоето неопределенное время

мне так не удобно, я делаю свои запросы\ответы и на основе их решаю - есть соединение или нет, но плохие каналы еще толком не тестировал

видел заметку «TCP Congestion Control или Почему скорость прыгает» https://habrahabr.ru/post/168407/, возможно она будет полезна

x905 ★★★★★ ()
Ответ на: комментарий от x905

насколько я понял tcp_keepalive «живет» в ядре

С точки зрения программы живёт оно в setsockopt

кроме как что оно оборвалось через какоето неопределенное время

С какой частотой кидать keepalive и сколько пакетов считать как «умерло» можно настраивать.

мне так не удобно, я делаю свои запросы\ответы и на основе их решаю - есть соединение или нет, но плохие каналы еще толком не тестировал

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

А кроме «есть соединение или нет» всё равно ничего толком узнать нельзя. То есть, можно, конечно, ещё и round-trip постоянно измерять, но смысла не вижу.

monk ★★★★★ ()
Ответ на: комментарий от x905

я делаю свои запросы\ответы и на основе их решаю - есть соединение или нет

А этот кусок у тебя в отдельную библиотеку не выделяется?

monk ★★★★★ ()
Ответ на: комментарий от monk

А этот кусок у тебя в отдельную библиотеку не выделяется?

нет, команды запроса\ответа я использую «по делу», время например возвращаю, выделять не планировал

возможно подумаю потом будет ли тут лучше keepalive или нет, надо придумать тесты и провести проверки

x905 ★★★★★ ()

тему не читал, но идеи есть: UDP с поддержкой таймаутов или STCP не нескольким каналам.

anonymous ()
Ответ на: комментарий от anonymous

Да просто над TCP свой простой type-length-value протокол с пользовательскими таймаутами. Старо как мир.

Deleted ()
Ответ на: комментарий от Deleted

свой простой type-length-value протокол с пользовательскими таймаутами

А готовый есть? С сишным интерфейсом.

monk ★★★★★ ()
Ответ на: комментарий от monk

А готовый есть? С сишным интерфейсом.

Это не столько протокол, сколько подход к созданию своего протокола, благодаря которому легко будет гонять свои keep-alive пакеты. Этот подход превращает TCP в «UDP over TCP»/SCTP. Кстати, в прошлом релизе ядра 4.6 наконец-то добавили эту возможность из-коробки: Kernel Connection Multiplexor, a facility for accelerating application layer protocols.

gag ★★★★★ ()

Но выглядит как-то костыльно. Кажется, что тогда проще на UDP накостылять свой надёжный протокол.

Да. Именно так. Именно поэтому многие протоколы ходят через udp или вообще через ip (как например vpn, передача видео, звука), тк tcp создавался совсем для других задач.

Полистай книжку Йон Снейдер «Эффективное программирование tcp/ip», там то, что тебе нужно в сжатом виде рассказано. И прям готовые болванки нужного софта скопипастишь.

anto215 ★★ ()

udp надежно?лол , используй 2 версию tcp или udp,хотя с реализацией их на сегодня хз.

NonameKiriLL ()
Ответ на: комментарий от Deleted

Будь мужиком, делай велосипеэд! :)

Велосипед у меня уже есть. Но, во-первых, не на Си, во-вторых хотелось бы ынтырпрайзнутости.

monk ★★★★★ ()
Ответ на: комментарий от dhampire

enet посмотри

Спасибо. Похоже на то, что надо.

monk ★★★★★ ()
Ответ на: комментарий от gag

Kernel Connection Multiplexor

спасибо! Не думал про этот мультиплексинг TCP в этом контексте. А вот оно как, оказывается.

Deleted ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.