Форум: "Сети";
Текущий архив: 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