Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.218.168.16] |
|
Страницы: (2) 1 [2] все ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
Спасибо, Oleg2004. Теперь кажется все ясно. Disconnect действительно просто инициировал процесс разъединения, но для его фактического убиения нужно было время. Если клиент пытался установить новое соединение до того, как старое убивалось, возникала ошибка Already connected. А использовать я это соединение повторно не мог, т.к. оно уже было "помечено" на удаление. Я правильно понял?
Считаю, что предложенный medved_68 вариант работы клиента и объяснение Oleg2004 полностью описывают решение проблемы Already connected. Уже вторые сутки тестирую свое приложение по новой схеме - сбоев не обнаружено. Поскольку топик посвящен правилам работы с соединениями в Indy, то не хотелось бы ограничиться только Already connected. Если кто сталкивался еще с какими-то необычными ситуациями (подводными камнями) при организции сеансов связи в Indy, просьба поделиться To Felan: А ты как использовал CheckForGracefulDisconnect()? Он при нарушенном соединении генерит исключение EIdException. Достаточно отловить его и обработать так, как считаешь нужным. По крайней мере у меня так работает |
Сообщ.
#17
,
|
|
|
try fIdClient.CheckForGracefulDisconnect( True ); aCMD.RawAnswer.Clear; try fIdClient.SendCmd(aCMD.CMD, 200); aCMD.WirteBinary(fIdClient.Socket); finally GetAllLines(aCMD.RawAnswer); end; except on e: EidReplyRFCError do aCMD.RawAnswer.Add(e.Message); on e: EIdConnClosedGracefully do aCMD.RawAnswer.Add(e.Message); end; EIdException это базовое... наверно можно и его использовать... я когда это писал планировал разную обработка по этим двум случаям. Еще вот это используется для установки доступности Action'ов function TiaKiosk.isConnected: Boolean; begin fIdClient.CheckForGracefulDisconnect( False ); Result := fIdClient.Connected; end; Ну и как я уже говорил в onDisconnect я делаю так try GetAllLines(vRA); except on e: EIdConnClosedGracefully do DoOnDisconnected( vRA ); end; Почему-то если не попытаться прочитать, то CheckForGracefulDisconnect не показывает адекватный результат. Даже если соединение уже закрыто, она говорит, что еще нет. |
Сообщ.
#18
,
|
|
|
Вот в чем прикол. Ты делаешь проверку CheckForGracefulDisconnect на клиенте, а я делал на сервере. На сервере вроде все работает. На клиенте я сейчас попробовал - действительно не работает. Причем пробовал два варианта:
Client.IOHandler.CheckForDisconnect(true, false); и Client.CheckForGracefulDisconnect(True); Зато вполне хорошо работает такой вариант: try if not Client.Connected then raise Exception.Create('Connection closed'); except Exit; end; Почему не работает первый вариант - действительно загадка |
Сообщ.
#19
,
|
|
|
Давайте вернемся к нашим баранам
Я не понимаю смысла проверки на клиенте с помощью спецфункции CheckForGracefulDisconnect() признака закрытия соединения со стороны сервера. В нормальных условиях таким признаком является возврат recv() нуля - именно сегмент FIN, полученный при нормальном завершении от сервера, заставляет recv() вернуть 0. Далее - есть такое суждение: Цитата CheckForDisconnect on the client. However for TCP to know the connection is down, it is often necessary to attempt to read/write to it. те если вы по каким-то причинам не поймали 0 от recv(), вы можете поймать признак завершения вышеописанным способом Те о чем я хочу сказать - мне непонятна логика той функциональности, которую вы требуете от клиента |
Сообщ.
#20
,
|
|
|
т.е. хочешь сказать, что на клиенте вообще не надо проверять есть соединение или нет, как только будет попытка что-то передать/прочитать тут все и выясниться?
А как детектировать аварийный обрыв в переиод когда нет непосредственной передачи? Т.е. например, послали команду. Она прошла. Получили ответ... Пользователь отошел. Т.к. активности на сокете нет. Связь рвется (кто-то шнур выдернул). Пользователь приходит, смотрит - связь есть. А мне например надо, что бы если вдруг связь оборвалась программа это определили и когда пользователь вернулся, он сразу увидел, что связи нет, и для этого ему не надо было бы что-то делать? |
Сообщ.
#21
,
|
|
|
Цитата Felan @ А мне например надо, что бы если вдруг связь оборвалась программа это определили Цитата Felan @ (кто-то шнур выдернул). Felan если дело только за тем, что нет сети (сетевой кабель не подключен), то обрабатывай соответствующее сообщение Винды и прибивай сокеты. Или же делай по таймеру пробную запись байта в канал и анализируй результат. Разумеется сервер должен "знать" об этом байте или цепочке байт и игнорировать их при приеме или показывать пользователю, что соединение активно. Хотя это все придумано, режим Keep-Aliving если не ошибаюсь. |
Сообщ.
#22
,
|
|
|
Да это я знаю.
Я так понял, что у Oleg2004 есть какое-то мега-знание... Хотел приобщиться. Может все это как-то более красиво реализовываться на Indy. |
Сообщ.
#23
,
|
|
|
Цитата Felan @ что у Oleg2004 есть какое-то мега-знание... Да вовсе нет - просто я достаточно хорошо знаю протоколы и сетевое программирование - а вот INDY знаю только поверхостно И если честно говорить, то только использование интерфейса сокетов дает полную свободу в сетевом программировании - компоненты этой свободы не имеют увы |
Сообщ.
#24
,
|
|
|
Сейчас занимаюсь проектом, связанным с сетевым программированием (в частности, протокол TCP).
Столкнулся с подобной проблемой. Объясню из-за чего она может возникать. 1. Сокет остался подключённым. Необходимо попробовать послать в него какие-либо данные и обработать исключение. 2. Остались данные во входящем буфере. Эта проблема часто возникает при неожиданном обрыве связи или тогда, когда ReadTimeout слишком мал (или же по техническим причинам клиент просто не дождался ответа. Этот вариант возникает чаще всего и именно он вводит программистов в ступор. Для решения проблемы необходимо очистить данный буфер после выполнения подключения, либо же до момента следующего подключения. Я пишу на С++, соответственно, это будет выглядеть так: TCPClient->Disconnect(true); if (!TCPClient->IOHandler->InputBufferIsEmpty()) { TCPClient->IOHandler->InputBuffer->Clear(); } Для Delphi, естественно: TCPClient.Disconnect(true); if not TCPClient.IOHandler.InputBufferIsEmpty then TCPClient.IOHandler.InputBuffer.Clear; Надеюсь, это поможет решить ваши проблемы |