![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Блокирующий TServerSocket [WinXP]
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, смысла нет.
Вы можете предложить что-либо другое? Буду рад услышать дельный совет :-)