Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Socket: Как удостовериться что связь в норме?

479  1 2 все
anly коренной житель16.03.17 20:47
anly
NEW 16.03.17 20:47 
Последний раз изменено 16.03.17 20:47 (anly)

задача на Сокетах в СИшарпе в режиме тсп-айпи и неблокируемом режиме.

Касается функций и свойств класса Socket: Listen, Accept, Connect, Receive, Send, Connected, Poll.


Есть сокет-сервер, который запускает Listen, а потом периодически Accept, пока не поймает сокeта-клиента, который вызвал Connect.

Итак связь установилась. Причем сервер работает только с одним клиентом, других (после того как с первого акцептировал, игнорирует).

Теперь сервер и клиент могут посылать друг другу сообщения , и принимать друг от друга. И вот например клиент отрубился (было вызвано Close), а потом опять хочет подконнектиться, но сервер его отбрасывает, пребывая в заблуждении что все еще на связи. Сервер просто периодически вызывает Receive, но понятно что данные не идут, а это нормально - клиент не шлёт, видимо потому что не надо.


Вопрос: как серверу узнать что связи уже нет? Ведь свойство Connected сокета полученного от Accept, всё еще возвращает True (проверенно дебагером). (Connected возвратит False, только после попытки Send, но это делать, только ради проверки связи, как-то некрасиво).


Как удостовериться что связь в норме? (без Send).

Проклят нарушающий межи ближнего своего (Втор.27:17)
#1 
NightWatch коренной житель16.03.17 22:01
NightWatch
16.03.17 22:01 
в ответ anly 16.03.17 20:47
но это делать, только ради проверки связи, как-то некрасиво).

Это распространенная практика. Тут нет ничего некрасивого.

#2 
Murr патриот16.03.17 22:02
Murr
NEW 16.03.17 22:02 
в ответ anly 16.03.17 20:47

http://stackoverflow.com/questions/722240/instantly-detect...


А по нормальному - нужен менеджер, который опросит сокеты и переподключит клиента.


было вызвано Close

-----

Перед ним еще Дисконнект рекомендуется.

#3 
NightWatch коренной житель16.03.17 22:10
NightWatch
NEW 16.03.17 22:10 
в ответ Murr 16.03.17 22:02
Перед ним еще Дисконнект рекомендуется.

А перед ним еще и Shutdown.

#4 
Murr патриот16.03.17 22:20
Murr
NEW 16.03.17 22:20 
в ответ NightWatch 16.03.17 22:10

Аааа... это Я перепутал - давно не сокетился...

#5 
  moose свой человек16.03.17 22:46
NEW 16.03.17 22:46 
в ответ anly 16.03.17 20:47, Последний раз изменено 16.03.17 22:48 (moose)
Как удостовериться что связь в норме? (без Send).

Читаем букварь:


Key Concept: A TCP connection is normally terminating using a special procedure where each side independently closes its end of the link. It normally begins with one of the application processes signalling to its TCP layer that the session is no longer needed. That device sends a FIN message to tell the other device that it wants to end the connection, which is acknowledged. When the responding device is ready, it too sends a FIN that is acknowledged; after waiting a period of time for the ACK to be received, the session is closed.


Если вышеописанная процедура не могла успешно завершиться (отсутствие физического соединения, например), то сервер попрежнему считает, что у него установлено соединение с клиентом. Клиент же уверен, что соединение закрыто. Рядовая ситуация. Воспроизводится для теста элементарно: из машины клиента или сервера выдергивается кабель и клиент "закрывает соединение".

#6 
AlexNek патриот17.03.17 01:33
AlexNek
NEW 17.03.17 01:33 
в ответ anly 16.03.17 20:47
Как удостовериться что связь в норме? (без Send).

Если и клиент и сервер свой то можно пробовать разные варианты. Если что чужое то лучше посылать watchdog телеграмму периодически.

И сделать конечно дополнительный треад для проверки соединения.

Но проблем будет еще много, самая интересная - обрубить синхронный слушающий сокет.

А при хорошей загрузке канала, нужно будет еще решать что лучше: приоритет передачи или приема и как их совместить? До определенного времени работает алгоритм: если нет что принимать, смотрим есть ли что послать.

А еще, что делать если соединение оборвалось, а пакеты хочется передать после восстановления.

#7 
anly коренной житель17.03.17 10:51
anly
NEW 17.03.17 10:51 
в ответ AlexNek 17.03.17 01:33

НП.


такой код вроде работает:

bool IsConnectionOK(Socket socket)

{

bool ok = false;
bool poll = socket.Poll(1000, SelectMode.SelectRead);

if (poll && socket.Available == 0)
ok = false;
else
ok = socket.Connected;


return ok;

}

Проклят нарушающий межи ближнего своего (Втор.27:17)
#8 
NightWatch коренной житель17.03.17 11:09
NightWatch
NEW 17.03.17 11:09 
в ответ anly 17.03.17 10:51, Последний раз изменено 17.03.17 11:15 (NightWatch)

И Socket.Poll и Socket.Available могут выбрасывать исключения.

Кроме того Socket.Poll

This method cannot detect certain kinds of connection problems, such as a broken network cable, or that the remote host was shut down ungracefully. You must attempt to send or receive data to detect these kinds of Errors.

Добавлю к списку рестарт находящихся между клиентом и сервером NAT-рутеров/файрволов или закрытие ими (по их мнению неактивных) портов.

#9 
LifeRider постоялец17.03.17 11:41
LifeRider
NEW 17.03.17 11:41 
в ответ anly 16.03.17 20:47
Вопрос: как серверу узнать что связи уже нет?

Только пинговать клиентов раз в какой-то интервал времени, клиент должен отвечать. Как только клиент на пинг не ответил - значит сдох (или связь, или клиент), делаем выводы.

Как удостовериться что связь в норме? (без Send).

100% гарантии (без пингования) не даст ни один метод.

#10 
Программист коренной житель17.03.17 18:51
NEW 17.03.17 18:51 
в ответ anly 16.03.17 20:47
Как удостовериться что связь в норме? (без Send).

Отрубаться по таймауту. Если кленту надо удерживать связь, то пусть он пингует сервер.

А сервер пусть тихо закрыват канал, если в течении какого-то времени от клиента ничего не пришло.

#11 
  moose свой человек17.03.17 19:27
NEW 17.03.17 19:27 
в ответ anly 16.03.17 20:47
запускает Listen, а потом периодически Accept, пока не поймает сокeта-клиента, который вызвал Connect.


Что значит "периодически"? Пока кто-нибудь не соединится, трэд висит на этом Accept().


Итак связь установилась. Причем сервер работает только с одним клиентом, других (после того как первого акцептировал), игнорирует.Теперь сервер и клиент могут посылать друг другу сообщения , и принимать друг от друга. И вот например клиент отрубился (было вызвано Close), а потом опять хочет подконнектиться, но сервер его отбрасывает, пребывая в заблуждении что все еще на связи. Сервер просто периодически вызывает Receive, но понятно что данные не идут, а это нормально - клиент не шлёт, видимо потому что не надо.

А клиент действительно только один, или их сотня, но мы будем соединяться только с первым попавшимся, остальные пускай ждут? Или что там происходит реально? Сервер как-то различает клиентов, они как-то регистрируются, или любой кто захотел соединиться, принимается?

Что делает тот трэд, который выдал Listen(), после того, как сработал Accept()?

Что предусмотрено нормальным сценарием на случай, если клиент закрыл соединение, и сервер об этом уведомлен?

#12 
LifeRider постоялец17.03.17 21:32
LifeRider
NEW 17.03.17 21:32 
в ответ Программист 17.03.17 18:51, Последний раз изменено 17.03.17 21:40 (LifeRider)
Если кленту надо удерживать связь, то пусть он пингует сервер.

Кстати да, не барское это дело - клиентов опрашивать. Стандартно по протоколу требуется именно пинг сервера от клиентов раз в заданный интервал (хотя мы часто и клиентов пингуем тоже, если протокол позволяет), иначе сервер просто молча отрубает соединение. :))

#13 
AlexNek патриот17.03.17 23:17
AlexNek
NEW 17.03.17 23:17 
в ответ anly 17.03.17 10:51
такой код вроде работает:

При своём коде в нормальных условиях будет почти всё работать.

Проблемы начинаются когда условия изменяются.

Для начала попробуйте нагло вынуть кабель на одной и на другой стороне. А после, его вставить, через пару секунд или через пару часов и больше. И потом еще приложение закрывать и открывать в отрубе.

У меня вот карта в устройстве (не комп) через какое то время начинает выдавать RST (Wireshark пользуем) и всё - соединению каюк. Пока никак не удаётся восстановить, так как после нового соединения опять приходит RST.

Гляньте также сколько "процессора" будет выжираться без передачи.

Потом начинаем непрерывно передавать данные и проверяем есть ли прием.

Также есть устройства которым пинг "не нравится"

И формат телеграм с протоколом продумайте хорошо.

#14 
anly коренной житель17.03.17 23:34
anly
NEW 17.03.17 23:34 
в ответ moose 17.03.17 19:27, Последний раз изменено 17.03.17 23:43 (anly)
Что значит "периодически"? Пока кто-нибудь не соединится, трэд висит на этом Accept().
я же сказал что в неблокируемом режиме. Т.е. поток не висит на Акцепт, а дергает периодически.
А клиент действительно только один, или их сотня, но мы будем соединяться только с первым попавшимся, остальные пускай ждут?
по техническому заданию возможна связь только с одним клиентом (если два оказалось то это ошибка юзера, впрочем ничего плохого не произойдет, просто второй клиент не свяжется). Более детально: речь идет о разработке функциональных блоков для приема/передачи на базе сокетов. Сами блоки юзеры будут вставлять в свои программы написанные наFBD, ST, IL, LD

Техзадание до конца еще не обдумано, т.е. в стадии разработки.

Что предусмотрено нормальным сценарием на случай, если клиент закрыл соединение, и сервер об этом уведомлен?
Хорошо если сервер это обнаружит и опять перейдет к дёрганью Акцептов.


Похоже что ситуацию обнаружения обрыва соединения (и рестарт) должны программировать сами юзеры. Просто хотелось бы облегчить им жизнь, но видно не получится.

Проклят нарушающий межи ближнего своего (Втор.27:17)
#15 
anly коренной житель17.03.17 23:37
anly
NEW 17.03.17 23:37 
в ответ AlexNek 17.03.17 23:17
Проблемы начинаются когда условия изменяются.
да я уже понял что полаться на этот код нельзя, раз даже майкрософт напрямую пишет что только Сендом можно связь проверить. Но код работает как минимум когда все сокеты на одном компьютере (в разных программах).
Проклят нарушающий межи ближнего своего (Втор.27:17)
#16 
  moose свой человек17.03.17 23:52
NEW 17.03.17 23:52 
в ответ anly 17.03.17 23:34
Что значит "периодически"? Пока кто-нибудь не соединится, трэд висит на этом Accept().
я же сказал что в неблокируемом режиме. Т.е. поток не висит на Акцепт, а дергает периодически.

Причем здесь "в неблокируемом режиме"? Можете привести кусок кода с listen, accept?

#17 
AlexNek патриот18.03.17 00:11
AlexNek
NEW 18.03.17 00:11 
в ответ anly 17.03.17 23:37
что только Сендом можно связь проверить.

Это да.

У меня сетевая либа больше года без проблем работала пока не начал её везде пользовать.

#18 
anly коренной житель18.03.17 00:25
anly
NEW 18.03.17 00:25 
в ответ moose 17.03.17 23:52

сокеты могут работать в блокируемом и неблокируемом режиме. В первом вызов Акцепт повесит поток пока клиент не вызовет Коннект. А во втором - Акцепт возвратит управление сразу сказав есть клиент или нет.

Проклят нарушающий межи ближнего своего (Втор.27:17)
#19 
NightWatch коренной житель18.03.17 08:07
NightWatch
NEW 18.03.17 08:07 
в ответ anly 17.03.17 23:34
Просто хотелось бы облегчить им жизнь, но видно не получится.
раз даже майкрософт напрямую пишет что только Сендом можно связь проверить.

Ну, так и воспользуйся советом Майкрософт. Что мешает?

#20 
1 2 все