Socket: Как удостовериться что связь в норме?
задача на Сокетах в СИшарпе в режиме тсп-айпи и неблокируемом режиме.
Касается функций и свойств класса Socket: Listen, Accept, Connect, Receive, Send, Connected, Poll.
Есть сокет-сервер, который запускает Listen, а потом периодически Accept, пока не поймает сокeта-клиента, который вызвал Connect.
Итак связь установилась. Причем сервер работает только с одним клиентом, других (после того как с первого акцептировал, игнорирует).
Теперь сервер и клиент могут посылать друг другу сообщения , и принимать друг от друга. И вот например клиент отрубился (было вызвано Close), а потом опять хочет подконнектиться, но сервер его отбрасывает, пребывая в заблуждении что все еще на связи. Сервер просто периодически вызывает Receive, но понятно что данные не идут, а это нормально - клиент не шлёт, видимо потому что не надо.
Вопрос: как серверу узнать что связи уже нет? Ведь свойство Connected сокета полученного от Accept, всё еще возвращает True (проверенно дебагером). (Connected возвратит False, только после попытки Send, но это делать, только ради проверки связи, как-то некрасиво).
Как удостовериться что связь в норме? (без Send).
http://stackoverflow.com/questions/722240/instantly-detect...
А по нормальному - нужен менеджер, который опросит сокеты и переподключит клиента.
было вызвано Close
-----
Перед ним еще Дисконнект рекомендуется.
Как удостовериться что связь в норме? (без 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.
Если вышеописанная процедура не могла успешно завершиться (отсутствие физического соединения, например), то сервер попрежнему считает, что у него установлено соединение с клиентом. Клиент же уверен, что соединение закрыто. Рядовая ситуация. Воспроизводится для теста элементарно: из машины клиента или сервера выдергивается кабель и клиент "закрывает соединение".
Как удостовериться что связь в норме? (без Send).
Если и клиент и сервер свой то можно пробовать разные варианты. Если что чужое то лучше посылать watchdog телеграмму периодически.
И сделать конечно дополнительный треад для проверки соединения.
Но проблем будет еще много, самая интересная - обрубить синхронный слушающий сокет.
А при хорошей загрузке канала, нужно будет еще решать что лучше: приоритет передачи или приема и как их совместить? До определенного времени работает алгоритм: если нет что принимать, смотрим есть ли что послать.
А еще, что делать если соединение оборвалось, а пакеты хочется передать после восстановления.
НП.
такой код вроде работает:
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;
}
И 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-рутеров/файрволов или закрытие ими (по их мнению неактивных) портов.
Вопрос: как серверу узнать что связи уже нет?
Только пинговать клиентов раз в какой-то интервал времени, клиент должен отвечать. Как только клиент на пинг не ответил - значит сдох (или связь, или клиент), делаем выводы.
Как удостовериться что связь в норме? (без Send).
100% гарантии (без пингования) не даст ни один метод.
запускает Listen, а потом периодически Accept, пока не поймает сокeта-клиента, который вызвал Connect.
Что значит "периодически"? Пока кто-нибудь не соединится, трэд висит на этом Accept().
Итак связь установилась. Причем сервер работает только с одним клиентом, других (после того как первого акцептировал), игнорирует.Теперь сервер и клиент могут посылать друг другу сообщения , и принимать друг от друга. И вот например клиент отрубился (было вызвано Close), а потом опять хочет подконнектиться, но сервер его отбрасывает, пребывая в заблуждении что все еще на связи. Сервер просто периодически вызывает Receive, но понятно что данные не идут, а это нормально - клиент не шлёт, видимо потому что не надо.
А клиент действительно только один, или их сотня, но мы будем соединяться только с первым попавшимся, остальные пускай ждут? Или что там происходит реально? Сервер как-то различает клиентов, они как-то регистрируются, или любой кто захотел соединиться, принимается?
Что делает тот трэд, который выдал Listen(), после того, как сработал Accept()?
Что предусмотрено нормальным сценарием на случай, если клиент закрыл соединение, и сервер об этом уведомлен?
Если кленту надо удерживать связь, то пусть он пингует сервер.
Кстати да, не барское это дело - клиентов опрашивать. Стандартно по протоколу требуется именно пинг сервера от клиентов раз в заданный интервал (хотя мы часто и клиентов пингуем тоже, если протокол позволяет), иначе сервер просто молча отрубает соединение. :))
такой код вроде работает:
При своём коде в нормальных условиях будет почти всё работать.
Проблемы начинаются когда условия изменяются.
Для начала попробуйте нагло вынуть кабель на одной и на другой стороне. А после, его вставить, через пару секунд или через пару часов и больше. И потом еще приложение закрывать и открывать в отрубе.
У меня вот карта в устройстве (не комп) через какое то время начинает выдавать RST (Wireshark пользуем) и всё - соединению каюк. Пока никак не удаётся восстановить, так как после нового соединения опять приходит RST.
Гляньте также сколько "процессора" будет выжираться без передачи.
Потом начинаем непрерывно передавать данные и проверяем есть ли прием.
Также есть устройства которым пинг "не нравится"
И формат телеграм с протоколом продумайте хорошо.
Что значит "периодически"? Пока кто-нибудь не соединится, трэд висит на этом Accept().я же сказал что в неблокируемом режиме. Т.е. поток не висит на Акцепт, а дергает периодически.
А клиент действительно только один, или их сотня, но мы будем соединяться только с первым попавшимся, остальные пускай ждут?по техническому заданию возможна связь только с одним клиентом (если два оказалось то это ошибка юзера, впрочем ничего плохого не произойдет, просто второй клиент не свяжется). Более детально: речь идет о разработке функциональных блоков для приема/передачи на базе сокетов. Сами блоки юзеры будут вставлять в свои программы написанные наFBD, ST, IL, LD
Техзадание до конца еще не обдумано, т.е. в стадии разработки.
Что предусмотрено нормальным сценарием на случай, если клиент закрыл соединение, и сервер об этом уведомлен?Хорошо если сервер это обнаружит и опять перейдет к дёрганью Акцептов.
Похоже что ситуацию обнаружения обрыва соединения (и рестарт) должны программировать сами юзеры. Просто хотелось бы облегчить им жизнь, но видно не получится.
Проблемы начинаются когда условия изменяются.да я уже понял что полаться на этот код нельзя, раз даже майкрософт напрямую пишет что только Сендом можно связь проверить. Но код работает как минимум когда все сокеты на одном компьютере (в разных программах).
Что значит "периодически"? Пока кто-нибудь не соединится, трэд висит на этом Accept().
я же сказал что в неблокируемом режиме. Т.е. поток не висит на Акцепт, а дергает периодически.
Причем здесь "в неблокируемом режиме"? Можете привести кусок кода с listen, accept?
сокеты могут работать в блокируемом и неблокируемом режиме. В первом вызов Акцепт повесит поток пока клиент не вызовет Коннект. А во втором - Акцепт возвратит управление сразу сказав есть клиент или нет.