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

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

Блокирующий TServerSocket [WinXP]


Страницы:   1 2

VaRela ©   (2007-10-19 12:49:00) 

Доброе время суток всем, борюсь со следующей проблемой:
TServerSocket работает в блокирующем режиме, создал своего наследника для потока TServerClientThread. В ClientExecute вертится следующий цикл (прошу прощения что BCB):

while (!Terminated && ClientSocket->Connected)
{
.....
}


Цикл работает отлично, но при отключении клиента НЕ ЗАВЕРШАЕТСЯ!,по всей видимости флаг ClientSocket->Connected не сбрасывается, никак не соображу почему.
Как можно узнать что клиент отключился?

P.S. Клиент не мой, переписать не смогу, протокола не знаю. :-)


Slym   (2007-10-22 04:29:00) [1]

Сергей М. ©   (19.10.07 15:26) [22]
aStream->ReadBuffer(Buf,1);

ну научил... :) так только дятлы делают причем в неволе :)
ReceiveBuf returns the number of bytes actually read. If no bytes are read, ReceiveBuf returns –1.
код чаргена - что здесь не понятно?
procedure TServerClientThreadEx.ClientExecute;
var
 Buf:array[byte] of char;
 i:integer;
begin
 try
   while (not Terminated) and ClientSocket.Connected do
   begin
     i:=ClientSocket.ReceiveBuf(Buf,SizeOf(Buf));
     if i=0 then
       ClientSocket.Close;
     ClientSocket.SendBuf(Buf,i);
   end;
 except
   Terminate;
   HandleException;
 end;
end;

если хочется с потоком TWinSocketStream:
procedure TServerClientThreadEx.ClientExecute;
var
 aStream:TWinSocketStream;
 Buf:array[byte] of char;
 i:integer;
begin
 try
   aStream:= TWinSocketStream.Create(ClientSocket, 10000);
   try
     while (not Terminated) and ClientSocket.Connected do
     begin
       if not aStream.WaitForData(aStream.TimeOut) then
       begin
         ClientSocket.Close;
         Continue;
       end;
       i:=aStream.Read(Buf,SizeOf(Buf));
       if i<=0 then
         ClientSocket.Close;
       aStream.WriteBuffer(Buf,i);
     end;
   finally
     aStream.Free;
   end;
 except
   Terminate;
   HandleException;
 end;
end;


VaRela   (2007-10-19 16:23:00) [2]

Во-первых, перед вызовом блок.метода ты можешь обратиться к ф-ции select(), в которой можно указать таймаут ожидания (т.е. повторить функциональность метода WaitForData).

Во-вторых, ты можешь перекрыть деструктор своего потока, в котором
закрыть гнездо, тогда блок.метод чтения/записи тут же завершится с исключением.


В любом случае спасибо за консультацию, очень Вам признателен :-)


Сергей М.   (2007-10-19 16:07:00) [3]


> цикл на этой функции зависнет до того как данные появятся,
>  я прав?


Прав.


> как тогда обрабатывать Terminate?


А вот здесь полный простор для творчества.

Во-первых, перед вызовом блок.метода ты можешь обратиться к ф-ции select(), в которой можно указать таймаут ожидания (т.е. повторить функциональность метода WaitForData).

Во-вторых, ты можешь перекрыть деструктор своего потока, в котором
закрыть гнездо, тогда блок.метод чтения/записи тут же завершится с исключением.


VaRela   (2007-10-19 15:34:00) [4]


> И вообще, зачем тебе TWinSocketStream ?
> Твоей задаче он идет как корове седло) .. Вполне достаточным
> будет использование методов send/receive-методы объекта
> ClientSocket

Дело в том, что если использовать только их, то цикл на этой функции зависнет до того как данные появятся, я прав? А как тогда обрабатывать Terminate?


Сергей М.   (2007-10-19 15:26:00) [5]


> Жаль функция ReadBuffer не возвращает размер полученных
> данных


А нафих он нужен ?

Если размер полученных данных не соответствует запрошенному размеру, стрим возбудит искл-е EReadError.

И вообще, зачем тебе TWinSocketStream ?
Твоей задаче он идет как корове седло) .. Вполне достаточным будет использование методов send/receive-методы объекта ClientSocket


VaRela   (2007-10-19 15:17:00) [6]

В общем вот что получилось

void __fastcall TicelinkServerThread::ClientExecute(void)
{
TWinSocketStream *aStream;
try
 {
 aStream = new TWinSocketStream(ClientSocket, 10000);
 try
  {
  while (!Terminated && ClientSocket->Connected)
   {
   Size = 0;
   if (aStream->WaitForData(1000))
    {
    try
     {
     aStream->ReadBuffer(Buf,1);
     }
    catch(...)
     {
     ClientSocket->Close();
     }
    Size = aStream->Read(&Buf[1],1024) + 1;
    }
   if (Size > 0)
    {
    Event = "Получено: " + AnsiString((char *)Buf);
    Synchronize(AddLOG);
    }
   }
  }
 __finally
  {
  delete aStream;
  }
 }
catch (Exception &E)
 {
 HandleException();
 }
ClientSocket->Close();
Event = "Поток завершился нафиг!";
Synchronize(AddLOG);
}


Вроде бы работает, но исполнение не очень нравится :-) Жаль функция ReadBuffer не возвращает размер полученных данных. :-(


Сергей М.   (2007-10-19 15:01:00) [7]


> исключение тоже не возникнет, ведь WaitForData возвращает
> true только в случае успешного получения данных в стрим


Как это не возникнет ?

Цитирую исх-к:

function TWinSocketStream.Read(var Buffer; Count: Longint): Longint;
var
 Overlapped: TOverlapped;
 ErrorCode: Integer;
begin
 FSocket.Lock;
 try
   FillChar(OVerlapped, SizeOf(Overlapped), 0);
   Overlapped.hEvent := FEvent.Handle;
   if not ReadFile(FSocket.SocketHandle, Buffer, Count, DWORD(Result),
     @Overlapped) and (GetLastError <> ERROR_IO_PENDING) then
   begin
     ErrorCode := GetLastError;
      raise ESocketError.CreateResFmt(@sSocketIOError, [sSocketRead, ErrorCode,
       SysErrorMessage(ErrorCode)]);
   end;
   if FEvent.WaitFor(FTimeOut) <> wrSignaled then
     Result := 0
   else
   begin
     GetOverlappedResult(FSocket.SocketHandle, Overlapped, DWORD(Result), False);
     FEvent.ResetEvent;
   end;
 finally
   FSocket.Unlock;
 end;
end;


VaRela   (2007-10-19 14:45:00) [8]


> > aStream->WaitForData(1000);
> Здесь нет анализа результата вызова этого метода.

Вот тут немного непонятно, если я сделаю вот так:
if (aStream->WaitForData(1000))
{
aStream->ReadBuffer(Buf,1024);
}

То исключение тоже не возникнет, ведь WaitForData возвращает true только в случае успешного получения данных в стрим.


Сергей М.   (2007-10-19 14:38:00) [9]


> Вы имели в виду методы ReceiveBuf и SendBuf? Я правильно
> понял?


И их в том числе.


Сергей М.   (2007-10-19 14:37:00) [10]


> разве эти методы работают в блокирующем режиме ?


А причем здесь режим ?
Это просто методы стрима.

А TWinSocketStream предназначен для использования именно  в блокирующемрежиме.

И в справке к методу Read четко сказано:

Unlike the ReadBuffer method, Read does not raise an exception if Count bytes are not read from the socket connection.


VaRela   (2007-10-19 14:30:00) [11]

Кстати, Вы имели в виду методы ReceiveBuf и SendBuf? Я правильно понял?


VaRela   (2007-10-19 14:26:00) [12]


> Стрим-методы Read и Write не возбуждают ожидаемого тобой
> исключения.
> Следует пользовать методы ReadBuffer, WriteBuffer.


Хм.. а разве эти методы работают в блокирующем режиме ?? В хелпе написано что они для неблокирующего :-/ Ща проверим-с.


Сергей М.   (2007-10-19 14:16:00) [13]


> Terminate();


Это убрать.


> aStream->WaitForData(1000);


Здесь нет анализа результата вызова этого метода.


> aStream->Read(Buf,1


Стрим-методы Read и Write не возбуждают ожидаемого тобой исключения.
Следует пользовать методы ReadBuffer, WriteBuffer.


VaRela   (2007-10-19 14:12:00) [14]

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


VaRela   (2007-10-19 13:53:00) [15]

Посмотрите пожалуйста вот на это:

void __fastcall TicelinkServerThread::ClientExecute(void)
{
TWinSocketStream *aStream;
try
 {
 aStream = new TWinSocketStream(ClientSocket, 10000);
 try
  {
  while (!Terminated && ClientSocket->Connected)
   {
   aStream->WaitForData(1000);
   try
    {
    Size = aStream->Read(Buf,1024);
    }
   catch(...)
    {
    ClientSocket->Close();
    Terminate();
    }
   if (Size > 0)
    {
    Event = "Received: " + AnsiString((char *)Buf);
    Synchronize(WriteIn);
    }
   }
  }
 __finally
  {
  delete aStream;
  }
 }
catch (Exception &E)
 {
 HandleException();
 }
ClientSocket->Close();
Event = "Поток завершился нафиг!";
Synchronize(AddLOG);
}


где я не прав? Не хочет работать :-(


Сергей М.   (2007-10-19 13:51:00) [16]


> отелось бы разобраться с блокирующим режимом


А что там разбираться ? Блок.режим намного проще, а как преодолеть "засаду", упомянутую в изначальном вопросе, я тебе уже рассказал.


VaRela   (2007-10-19 13:47:00) [17]


> Значит у тебя ошибка в программе.


Возможно, но всё таки хотелось бы разобраться с блокирующим режимом, так как в дальнейшем планирую наращиваь функционал.


Сергей М.   (2007-10-19 13:46:00) [18]


> Вы можете предложить что-либо другое?


stNonBlocking, что же еще ..


> при попытке работы с несколькими клиентами начинается просто
> бред


Значит у тебя ошибка в программе.


VaRela   (2007-10-19 13:41:00) [19]

В настоящий момент есть рабочая версия программы, в неблокирущем режиме, отлично работает с ОДНИМ приложением-клиентом но при попытке работы с несколькими клиентами начинается просто бред :-)


VaRela   (2007-10-19 13:40:00) [20]

To Сергей М.


> Ради туннеля между всего двумя хостами городить огород с
> thread blocking режимом сервера, imho, смысла нет.


Вы можете предложить что-либо другое? Буду рад услышать дельный совет :-)


Страницы:   1 2

Наверх

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