Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Отследить дисконнект клиентского сокета [D7, WinXP]


SpellCaster ©   (2006-10-18 17:00:00) 

Продолжаю доставать сообщество своими траблами с сокетами :).
Имеется две программы, общаются между собой через блокирующие TClient\ServerSocket.  Работа сервера выполняется в TServThread = class(TServerClientThread) (экземпляр потока получается при коннекте клиента в Server.OnGetThread), за обмен данными отвечает fSocketStream:=TWinSocketStream.Create(ClientSocket,3000).

Вопрос в следующем: как на сервере отследить, что клиент отсоединился? Хоть я и закрываю клиентский сокет при выходе из проги, сервер на это не реагирует. Я пробовал проверять всё, что только можно:
ClientSocket.Connected
ServerSocket.ActiveConnections
ServerSocket.ActiveThreads
ServerSocket.Connections[0].Connected
- и все эти св-ва исправно докладывают, что соединение есть!


Сергей М.   (2006-10-19 16:59:00) [1]


> SpellCaster   (19.10.06 16:53) [19]


И в этом случае она тоже обязана "отпустить".


SpellCaster   (2006-10-19 16:53:00) [2]


> Кр.того, она "отпустит" и в том случае, если "инфа в канал
> не поступила", но партнер в момент "виса" на блокирующем
> ReceiveBuf() закроет соединение по своей инициативе.

А если не закроет по своей инициативе? Если вылетит, к примеру? Или уборщица провод выдернет ;)


Сергей М.   (2006-10-19 15:45:00) [3]


> SpellCaster   (19.10.06 15:14) [16]


> ощущение, что мы говорим на разных языках


Похоже на то.
Но истина - она одна)


> если запустить ReceiveBuf, когда соединение еще не закрыто,
>  он повиснет до тех пор, пока в канал не поступит инфа.
> Так?
>
>


Так.
Кр.того, она "отпустит" и в том случае, если "инфа в канал не поступила", но партнер в момент "виса" на блокирующем ReceiveBuf() закроет соединение по своей инициативе.


SpellCaster   (2006-10-19 15:43:00) [4]

Хм, сделал с WaitForData


  len:=fSocketStream.Read(fBuf^,MaxMsgLen);
  if len=0 then // если ничего не получено - начинаем отсчитывать таймаут и усыпляем поток на некоторое время
  begin
   if not fSocketStream.WaitForData(10000) then Terminate else
   begin
    Sleep(300);
    clientsocket.ReceiveBuf(c,1);
    Continue;
   end;
  end;

Что в результате: обмениваемся данными, потом закрываем клиента - и WaitForData возвращает True! Заходим соответственно в цикл, читаем байт, ничего не получаем и на новую итерацию. И так без конца.
Пожалуй, всё-таки буду отслеживать время последнего обмена инфой.


SpellCaster   (2006-10-19 15:14:00) [5]


> Не верно.
> Блокирующий вызов ReceiveBuf(), вернувший 0, фиксирует факт
> корректного закрытия соединения по инициативе партнера.

У меня такое ощущение, что мы говорим на разных языках...

> Да, но в том случае, если соединение ещё не завершено, она
> бесконечно ждётпоявления в канале хоть какой-то инфы!

Повторю по-другому: если запустить ReceiveBuf, когда соединение еще не закрыто, он повиснет до тех пор, пока в канал не поступит инфа. Так?


> А не проще ли использовать WaitForData??? тогда  если в
> течении какого то времени от клиента нет ответа и возврат
> из WaitForData <> WAIT_OBJECT_0 то принимается решение о
> смерти клиента и прибитии потока.

В принципе, да. Получится нечто вроде отслеживания времени неактивности канала, как в [9]. Наверно, так и сделаю.


medved_68   (2006-10-19 14:59:00) [6]

SpellCasterА не проще ли использовать WaitForData??? тогда  если в течении какого то времени от клиента нет ответа и возврат из WaitForData <> WAIT_OBJECT_0 то принимается решение о смерти клиента и прибитии потока. Соответственно с выходом на событие ThreadEnd. :)))


Сергей М.   (2006-10-19 14:08:00) [7]


> SpellCaster   (19.10.06 13:53) [13]


Не верно.

Блокирующий вызов ReceiveBuf(), вернувший 0, фиксирует факт корректного закрытия соединения по инициативе партнера.


SpellCaster   (2006-10-19 13:53:00) [8]


> .. и это есть факт корректного закрытия соединения по инициативе партнера.

Да, но в том случае, если соединение ещё не завершено, она бесконечно ждёт появления в канале хоть какой-то инфы!


Сергей М.   (2006-10-19 12:51:00) [9]


> SpellCaster   (19.10.06 12:34) [11]



> clientsocket.ReceiveBuf(c,1); считается таковой? Если да,
>  то никакой пользы от нее нет - она читает 0 байт и ....


.. и это есть факт корректногозакрытия соединения по инициативе партнера.


SpellCaster   (2006-10-19 12:34:00) [10]


> Сергей М.



> Все правильно.
> Если искл-я нет, то партнер заведомо "жив".


> Но при любой причине "смерти" гарантия ее своевременного
> обнаружения - своевременный вызов любой из транспортных
> ф-ций.

А clientsocket.ReceiveBuf(c,1); считается таковой? Если да, то никакой пользы от нее нет - она читает 0 байт и идёт дальше при закрытом приложении клиента.

Идея насчёт таймаута неплохая. Встрою её до кучи.


Сергей М.   (2006-10-19 12:14:00) [11]


> medved_68 ©   (19.10.06 11:58) [9]


> время жизни сокетного потока при отсутствии активности в
> сокете


Вариант опять же сводится к определению факта "смерти" партнера.

Партнер же может "умереть" и не по своей воле (самое распространенная "смерть" - тётьнюра-уборщица со всей дури дернула шваброй за "жизнеобеспечивающий" провод компьютера)

Но при любой причине "смерти" гарантия ее своевременного обнаружения - своевременный вызов любой из транспортных ф-ций.


medved_68   (2006-10-19 11:58:00) [12]


> Ну это уже претензии к Борману/Мелкософту ;)

Да нет!!! Они то тут как раз и ни при чем! :))
> Согласен, я так и сделал. Но хочется убедиться, что более
> простых вариантов нет.

Еще один вариант - время жизни сокетного потока при отсутствии активности в сокете


Сергей М.   (2006-10-19 11:29:00) [13]


> SocketStream по идее при ошибке чтения из сокета вызывает
> исключение


Все правильно.
Если искл-я нет, то партнер заведомо "жив".


umbra   (2006-10-19 11:28:00) [14]

или клиент может посылать сообщения, что жив. Если сообщений нет х минут/секунд/часов - значит клиент умер.


SpellCaster   (2006-10-19 11:20:00) [15]


> SpellCaster у тебя  ошибка в программе потока, который не
> проверяет жизнеспособность клиента.

Ну так в том-то и вопрос: КАК проверить жизнеспособность клиента!

> В любом случае циркуляция потока и его работоспособность
> после разрыва очень ПОДОЗРИТЕЛЬНА. Так быть не должно. :)))

Ну это уже претензии к Борману/Мелкософту ;)

> клиент может посылатю сообщение, что он отключается.

Согласен, я так и сделал. Но хочется убедиться, что более простых вариантов нет.


umbra   (2006-10-19 11:17:00) [16]

клиент может посылатю сообщение, что он отключается.


medved_68   (2006-10-19 11:09:00) [17]


> В том-то и дело, что этот поток отлично себе циркулирует
> после закрытия клиента. События, естественно, никакого не
> происходит.

SpellCasterу тебя  ошибка в программе потока, который не проверяет жизнеспособность клиента. В любом случае циркуляция потока и его работоспособность после разрыва очень ПОДОЗРИТЕЛЬНА. Так быть не должно. :)))


SpellCaster   (2006-10-19 10:58:00) [18]


> medved_68

В том-то и дело, что этот поток отлично себе циркулирует после закрытия клиента. События, естественно, никакого не происходит.


> Сергей М.

Мда, я так примерно и думал. Ну, с send понятно. А как насчет recv - ведь этот кусочек проходится нормально:


  len:=fSocketStream.Read(Buf^,MaxMsgLen);
  if len=0 then begin Sleep(300); Continue; end; // если ничего не получено


Возвращается 0, и цикл преспокойно катится дальше, хотя SocketStream по идее при ошибке чтения из сокета вызывает исключение. Как же определить, что соединение уже разорвано?
Попробовал вставить чистое чтение сокета, не через поток:

   clientsocket.ReceiveBuf(c,1);

Всё проходится на ура. Как быть? Не писать же тестовый байт в поток!
Пока что сделал так: при закрытии клиент посылает серверу команду дисконнекта, тот ее принимает и завершает поток. Вроде бы неплохо, но хочется выяснить, нельзя ли сделать проще.


Сергей М.   (2006-10-19 10:32:00) [19]


> все эти св-ва исправно докладывают, что соединение есть


В блок.режиме факт корректного разрыва соединения по инициативе партнера  может быть обнаружен тольков ходе выполнения той или иной блокирующей ф-ции ввода/вывода (send/recv).


medved_68   (2006-10-19 10:19:00) [20]


> Вопрос в следующем: как на сервере отследить, что клиент
> отсоединился? Хоть я и закрываю клиентский сокет при выходе
> из проги, сервер на это не реагирует.

SpellCasterА что на сервере поток обслуживающий это клиентское соединение живет после его закрытия???? И если да то первый вопрос: "С какого перепугу?"  И если нет, то второй вопрос:
"А для чего придумано событие ServerSocketa OnThreadEnd???" :)))


Наверх

Титульная страница Поиск, карта сайта Написать письмо