Socket KeepAlive или формирование второго канала передачи данных.
От: LWhisper  
Дата: 03.10.18 12:41
Оценка:
Коллеги, доброго дня.

Есть клиент-серверное приложение. С одной стороны выполняется Socket.Send, с другой — Socket.Receive. Всё это обёрнуто в NetworkStream с кучей обёрток поверх, но это уже не важно.

В один прекрасный момент пропадает связь между клиентом и сервером. В этот момент отправитель отваливается на Socket.Send и закрывает коннекцию — информация о закрытии коннекции теряется. По этой причине получатель ничего не знает о том, что данных не будет и продолжает висеть.

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

Проблема в том, что в протокол не заложена информация об изменении состояния запроса и отсутствует подтверждение доставки. Чтобы не ломать обратную совместимость и избавить себя от необходимости вкручивать различные таймауты на каждую операцию и механизмы их анализа для ретраев, хочется заиметь способ ручного управления кипалайвами. Раз в минуту поток из пула посылает в канал KeepAlive'а пакет. Если за 10 минут по каналу KeepAlive'а не пришло ни одного пакета, соединение рубится.

И вот тут встаёт вопрос — а как получить этот второй канал передачи? Out-of-band data вычеркиваем — любой роутер без поддержки разломает столь изящное решение. Windows 95 вообще уходила от них в синьку. Не знаю, изменилось ли что-нибудь в лучшую сторону с тех пор. Что ещё можно сделать? Как получить второй, независимый канал передачи данных, имея на руках только подключённый Socket?

Повторное подключение не подходит — переделок будет столько, что проще сразу сделать хорошо. Сразу делать хорошо сейчас не хочется. Ищу адекватный костыль.

Спасибо за любые идеи.
.net socket tcp tcp/ip network keepalive keepconnection
Re: Socket KeepAlive или формирование второго канала передачи данных.
От: takTak  
Дата: 03.10.18 12:57
Оценка:
LW> за любые идеи.

не хочешь потренироваться на кошках с SignalR?

или у тебя какое-то древнее железо? почему именно сокеты?
Re: Socket KeepAlive или формирование второго канала передач
От: takTak  
Дата: 03.10.18 13:41
Оценка:
LW>В один прекрасный момент пропадает связь между клиентом и сервером. В этот момент отправитель отваливается на Socket.Send и закрывает коннекцию — информация о закрытии коннекции теряется. По этой причине получатель ничего не знает о том, что данных не будет и продолжает висеть.


вот тут чувак пишет, что если интервал для KeepAlive сделан соответствующе маленьким, то в ответе ACK flag будет не установлен: это сигнал о том, что соединение отвалилось
это было со стороны сервера...

со стороны клиента установить нарушения сложнее, кто-то предлагает использовать пинг, но не знаю, как это всё согласуется с рутерами
https://docs.microsoft.com/en-us/dotnet/api/system.net.networkinformation.ping?redirectedfrom=MSDN&view=netframework-4.7.2

оказывается, с самого клиента ещё можно статус соединения через поллинг перепроверять:
https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.poll?redirectedfrom=MSDN&view=netframework-4.7.2#System_Net_Sockets_Socket_Poll_System_Int32_System_Net_Sockets_SelectMode_
Отредактировано 03.10.2018 15:00 takTak . Предыдущая версия . Еще …
Отредактировано 03.10.2018 13:49 takTak . Предыдущая версия .
Re: Socket KeepAlive или формирование второго канала передач
От: Nikolay_Ch Россия  
Дата: 03.10.18 14:34
Оценка:
Здравствуйте, LWhisper, Вы писали:

LW>В один прекрасный момент пропадает связь между клиентом и сервером. В этот момент отправитель отваливается на Socket.Send и закрывает коннекцию — информация о закрытии коннекции теряется. По этой причине получатель ничего не знает о том, что данных не будет и продолжает висеть.

Не совсем понятно, у Вас остается висеть recv на получателе? Если send отвалился, это еще не значит, что соединение оборвалось. Таймаут у TCP достаточно большой же.

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

Как сокет на отправителе жив, если Вы написали, что соединение закрывается?

LW>Проблема в том, что в протокол не заложена информация об изменении состояния запроса и отсутствует подтверждение доставки. Чтобы не ломать обратную совместимость и избавить себя от необходимости вкручивать различные таймауты на каждую операцию и механизмы их анализа для ретраев, хочется заиметь способ ручного управления кипалайвами. Раз в минуту поток из пула посылает в канал KeepAlive'а пакет. Если за 10 минут по каналу KeepAlive'а не пришло ни одного пакета, соединение рубится.

А почему нельзя тупо сделать тогда единый таймаут на получение данных? Если нет посылок, то рубить соединение?

LW>Повторное подключение не подходит — переделок будет столько, что проще сразу сделать хорошо. Сразу делать хорошо сейчас не хочется. Ищу адекватный костыль.

Почему не подходит? Открыть повторное подключение в независимом модуле/классе с событием — соединение потеряно. Если что не так — соединение перезапускается. В основную программу в трек отправления/получения данных встраивается один if и все.
Отредактировано 03.10.2018 14:35 Nikolay_Ch . Предыдущая версия .
Re: Socket KeepAlive или формирование второго канала передачи данных.
От: Neco  
Дата: 06.10.18 08:59
Оценка:
Здравствуйте, LWhisper, Вы писали:

LW>Коллеги, доброго дня.


LW>Проблема в том, что в протокол не заложена информация об изменении состояния запроса и отсутствует подтверждение доставки.

Тут надо знать протокол, чтобы что-то предложить. Когда я выдумываю свои протоколы, они всегда вида Type-Length-Data (ну и я этот принцип слизал у ICQ в своё время, так что наверное все так делают). В таком случае можно просто добавить новый тип пакета.
Если такого в протокол не заложено, можно сделать VirtualStream (подменив им изначальный NetworkStream), который будет пересылать данные в виде Type-Length-Data и тем самым эмулировать второй канал передачи данных — грубо говоря текущий поток данных будет пересылаться с Type=1, а второй канал с Type=2.
всю ночь не ем, весь день не сплю — устаю
Re: Socket KeepAlive или формирование второго канала передачи данных.
От: Neco  
Дата: 06.10.18 09:08
Оценка:
Здравствуйте, LWhisper, Вы писали:

Кстати, вот эти два предложения не очень между собой стыкуются:
LW>...В этот момент отправитель отваливается на Socket.Send и закрывает коннекцию — информация о закрытии коннекции теряется...
LW>...Но поскольку сеть и сокеты с обеих сторон живы, они успешно сигнализируют о том, что сетка жива...
с одной стороны сокет должен ведь мёртвым, нет?
когда я свой мессенждер на сокетах писал (в 2003-ем) у меня как раз не было проблемы, если при отправке обнаруживалось отсутствие связи. Проблема была в случае, если ничего не слалось, а сеть падала — от винды не было никакого сигнала об этом и обе стороны думали, что соединение живо.
Чаще всего клиент при последующей отправке фейлился и пытался переподключиться. А вот сервер по-моему пребывал в состоянии "связь жива" до следующего соединения со стороны клиента. Ну и да — решалось контрольными пакетами.
всю ночь не ем, весь день не сплю — устаю
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.