Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2008.08.31;
Скачать: [xml.tar.bz2];

Вниз

Блокирующий TServerSocket   Найти похожие ветки 

 
VaRela   (2007-10-19 12:49) [0]

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

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


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

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


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


> Как можно узнать что клиент отключился?


По факту возбуждения исключения при вызове любого из методов приема или передачи. В обработчике исключения вызываешь ClientSocket.Close и на следующей итерации благополучно вываливаешься из цикла.


> переписать не смогу, протокола не знаю


Не понял .. Как же ты пишешь сервер, если не знаешь протокола ? Или ты порт-маппер сочиняешь ?


 
Slym ©   (2007-10-19 13:02) [2]

TServerSocket по умолчание кеширует потоки...
т.е. поток не терминируется а приостанавливается для дальнейшего использования


 
Сергей М. ©   (2007-10-19 13:11) [3]


> Slym ©   (19.10.07 13:02) [2]


Это ты к чему ?


 
VaRela   (2007-10-19 13:14) [4]


> Не понял .. Как же ты пишешь сервер, если не знаешь протокола
> ? Или ты порт-маппер сочиняешь ?

По сути дела это тоннель, но с обратной логикой, т.е. существует два компьютера, на одном из которых запрещены все входящие соединения, вот на этот компьютер необходимо подключаться, например радмином. Поэтому на этот комп ставится клиентская часть (моя), которая коннектится к моей же серверной части (на втором компе), и устанавливает перманентное соединение, а уже по этому соединению должны передаваться данные в обе стороны. На клиенте так же установлен и серверный сокет, который слушает любые приложения-клиенты и транслирует всё что от них получает в установленное соединение. Ну и в обратную сторону тоже соответственно

> По факту возбуждения исключения при вызове любого из методов
> приема или передачи. В обработчике исключения вызываешь
> ClientSocket.Close и на следующей итерации благополучно
> вываливаешься из цикла.

Хорошая идея кстати, сейчас попробую, большое спасибо за совет :-)
Не уходите далеко, возможно у меня не получится ;-)


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

To Slym


> TServerSocket по умолчание кеширует потоки...
> т.е. поток не терминируется а приостанавливается для дальнейшего
> использования


Да я в курсе, но поток хоть и не разрушается, но всё же должен останавливаться, а в моем случае он крутит цикл пока я не сделаю Server->Close();


 
Сергей М. ©   (2007-10-19 13:29) [6]


> VaRela   (19.10.07 13:14) [4]


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


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

To Сергей М.


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


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


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

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


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


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


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


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


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


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


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


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


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


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


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


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

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

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);
}


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


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

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


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


> Terminate();


Это убрать.


> aStream->WaitForData(1000);


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


> aStream->Read(Buf,1


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


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


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


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


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

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


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


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


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

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

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

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


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


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


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


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


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

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

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


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


> исключение тоже не возникнет, ведь 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 15:17) [21]

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

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:26) [22]


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


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

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

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


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


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

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


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


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


Прав.


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


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

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

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


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

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

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


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


 
Slym ©   (2007-10-22 04:29) [26]

Сергей М. ©   (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;



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

Форум: "Сети";
Текущий архив: 2008.08.31;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.53 MB
Время: 0.007 c
2-1216793238
TUserClass
2008-07-23 10:07
2008.08.31
Кнопочка на табе (заголовке) у TabSheet.


2-1216802282
artkil
2008-07-23 12:38
2008.08.31
Запрет изменения текста в TRichEdit


2-1216988088
ketanov
2008-07-25 16:14
2008.08.31
WebModule


2-1216845572
Terasbetoni
2008-07-24 00:39
2008.08.31
Как устанавливать библиотеки? В частности GLScene.


2-1216835667
valer4
2008-07-23 21:54
2008.08.31
try..finally





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский