Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.07.20;
Скачать: CL | DM;

Вниз

WinSock и Disconnect   Найти похожие ветки 

 
BOBik   (2007-09-24 13:49) [0]

Хотел написать простенкое клиент-серверное приложение на WinAPI, но сталкнулся с проблемой:
сервер ждет от клиента сообщение (функция recv), программа не продолжает работу пока функция не отработает, но вот проблема, если клиент внезапно отключается, то сервер все равно ждет от него сообщений!
Как обработать дисконнект клиента???
Я думал, что если клиент отключится, то функция recv вернет ошибку, но она этого не делает.


 
Сергей М. ©   (2007-09-24 13:56) [1]


> клиент внезапно отключается


Что подразумевается под "отключается" ?


 
Сергей М. ©   (2007-09-24 14:29) [2]

Цитата из http://book.itep.ru/4/44/tcp_443.htm :

Будучи однажды создан, канал TCP может существовать "вечно". Если клиент и сервер пассивны, они не заметят того, например, что какой-то бульдозер оборвал кабель или спутник связи покоится на дне океана. Чтобы это обнаружить, либо клиент либо сервер должны попытаться послать какую-то информацию. Чтобы информировать систему об этих и подобных им жизненных неурядицах, предусмотрен таймер контроля работоспособности (keepalive). Многим читателям, возможно, приходилось легкомысленно выключать питание своего персонального компьютера, не позаботившись о корректном logout из процедуры telnet или FTP. Если бы не существовало этого таймера, включив ЭВМ, вы бы обнаружили, что "находитесь" в заморском депозитарии, где были вчера. Но таймер контроля работоспособности может и прервать сессию, если какой-то промежуточный маршрутизатор произвел перезагрузку или был вынужден поменять маршрут. Принцип работы таймера работоспособности предельно прост. Если канал пассивен, например, 2 часа, сервер посылает клиенту сегмент-зонд. При этом ЭВМ-клиент может быть в одном из четырех состояний.

   * Работоспособен и достижим для сервера. Отклик от клиента сбросит таймер работоспособности в ноль (начало отсчета очередных двух часов).
   * Вышел из строя, выключен или перезагружается. Сервер посылает 10 запросов с интервалом 75 сек. Если отклика нет, канал закрывается и со стороны сервера.
   * Перезагрузился. Сервер получит отклик типа RESET и канал будет закрыт.
   * Работоспособен, но не достижим для сервера. Случай тождественен, описанному во втором по порядку пункте.

Временная постоянная таймера keepalive является системной переменной единой для всех пользователей ЭВМ или даже локальной сети.


 
BOBik   (2007-09-24 14:38) [3]

Отключается- например комп-клиент выключился или завершился процесс.
кусок кода сервера следующий:

begin
ZeroMemory(@buffer, 1024);
if recv(socket^, buffer, 1024, 0)=SOCKET_ERROR then //получаем данные из сокета
....


Так вот дойдя до if recv(socket^.... программа останавливается, и ждет получения данных. В этот момент у меня вышел из строя другой компьютер(на котором был запущен программа-клиент, от которой сервер ждал сообщений), а программа-сервер так и осталась ждать данных :(
Как этого можно избежать?


 
DVM ©   (2007-09-24 14:47) [4]


> а программа-сервер так и осталась ждать данных :(

укажи в select() таймаут или используй неблокирующие сокеты


 
BOBik   (2007-09-24 14:48) [5]

сначала я писал просто

recv(socket^, buffer, 1024, 0);

потом поглядел исходники тут: http://forum.sysman.ru/index.php?showtopic=11136
там было:

....
while( (int bytes_recv=
recv(my_sock,&buff[0],sizeof(buff),0))
&& bytes_recv !=SOCKET_ERROR)
send(my_sock,&buff[0],bytes_recv,0);

// если мы здесь, то произошел выход из цикла по
// причине возращения функцией recv ошибки –
// соединение клиентом разорвано
nclients--; // уменьшаем счетчик активных клиентов
printf("-disconnect\n"); PRINTNUSERS
....

Вот и решил что

...
if recv(socket^, buffer, 1024, 0)=SOCKET_ERROR then
...

мне должно помочь.


 
DVM ©   (2007-09-24 14:49) [6]

Вот пример (который не стоит слепо копировать, т.к. он немного специфический), но суть ясна я думаю


function THTTPInputThread.ReadData(ABuffer: TBuffer; BytesExpected: integer): integer;
const
 MaxLen = 262144;
var
 TotalBytesToRead, Found, TotalBytesRead, BytesToRead, BytesRead: integer;
 Rfds: TFDSet;
 TempBuff: array [0..Pred(MaxLen)] of Char;
begin
 FD_ZERO(Rfds);
 FD_SET(Sock, Rfds);
 Found := select(Sock, @Rfds, nil, nil, @FTimeout);
 if Found = 0 then
   begin
     // Select timed out
     Result := -1;
     exit;
   end
 else
   if Found = SOCKET_ERROR then
     begin
       // Select error
       Result := -1;
       exit;
     end;
 TotalBytesToRead := 0;
 if BytesExpected <> 0 then
   begin
     TotalBytesToRead := BytesExpected;
   end
 else
   begin
     if ioctlsocket(Sock, FIONREAD, TotalBytesToRead) = SOCKET_ERROR then
       begin
         // Cannot ioctl()
         Result := -1;
         exit;
       end;
     if TotalBytesToRead = 0  then
       begin
         SocketDisconnect();
         Result := 0;
         exit;
       end;
   end;
 TotalBytesRead := 0;
 repeat
   if TotalBytesToRead > MaxLen then
     BytesToRead := MaxLen
   else
     BytesToRead := TotalBytesToRead;
   ZeroMemory(@TempBuff[0], MaxLen);
   BytesRead := recv(Sock, TempBuff, BytesToRead, 0);
   if BytesRead = SOCKET_ERROR then
     begin
       // Read error
       SocketDisconnect();
       Result := -1;
       exit;
     end
   else
     if BytesRead = 0 then
       begin
         SocketDisconnect();
         Result := 0;
         exit;
       end
     else
       begin
         if ABuffer.Size >= 2097152 then
           begin
             SocketDisconnect();
             Result := -1;
             exit;
           end;
         ABuffer.Append(@TempBuff[0], BytesRead);
         TotalBytesRead := TotalBytesRead + BytesRead;
         TotalBytesToRead := TotalBytesToRead - BytesRead;
       end;
 until TotalBytesToRead <= 0;
 Result := TotalBytesRead;
end;


 
Anatoly Podgoretsky ©   (2007-09-24 14:51) [7]

> BOBik  (24.09.2007 14:38:03)  [3]

Должна отвалиться, иначе бы хакеры давно убили бы Интернет.


 
Сергей М. ©   (2007-09-24 14:51) [8]


> Как этого можно избежать?


Ты в [2] вник ?


 
DVM ©   (2007-09-24 14:52) [9]


> Должна отвалиться

она и отваливается через секунд 20 у него, только он не дожидался


 
BOBik   (2007-09-24 14:56) [10]

ок, спасибо за пример :)


 
BOBik   (2007-09-24 15:09) [11]

блин... мне стыдно :( внатуре отпала....
Спасибо огромное за советы, по таймеру я все таки сделаю :))
С-П-А-С-И-Б-О
P.s. Я вроде долго ждал- не отваливалась :)


 
Сергей М. ©   (2007-09-24 15:10) [12]


> она и отваливается через секунд 20


Может и отвалиться. Но в общем случае не обязана.


 
Сергей М. ©   (2007-09-24 16:30) [13]

Вообще-то keepalive для таких чудиков придуман



Страницы: 1 вся ветка

Текущий архив: 2008.07.20;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.02 c
2-1214192033
NewSer
2008-06-23 07:33
2008.07.20
Как программно настроить связь TQRChart с БД? (ADO)


2-1213869168
NeiL
2008-06-19 13:52
2008.07.20
Компонент


6-1190641100
Кихтенко Андрей
2007-09-24 17:38
2008.07.20
Indy SSL Apache. Help!


2-1213610401
masv
2008-06-16 14:00
2008.07.20
изменить размер шрифта при печати сетки


1-1195553133
DVM
2007-11-20 13:05
2008.07.20
TWinControl.WMPaint от Delphi7 запостите пожалуйста.