![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TClientSocket в TThread не работает... [D6, Win95/98]
Donal_Graeme © (2002-04-10 18:09:00)ничего не понимаю...
в главной форме работает, внутри метода потока Execute - не работает. один и тот же код :
FTCP.Host := Host;
FTCP.Port := StrToInt (Port);
FTCP.ClientType := ctNonBlocking;
FTCP.Open;
если в потоке, то работает так:
если Host задать неправильно, то он вываливается с ошибкой, т.е. работает, а если Host задан правильно, то коннекта не происходит и ошибок тоже не возникает.
хотя в основной программе коннектится и нормально работает.
Donal_Graeme (2002-04-11 15:53:00) [21]извиняюсь за сумбур :-))
в ctBlocking работает, в ctNonBlocking - не работает
Digitman (2002-04-11 15:53:00) [22]>Reindeer Moss Eater
>>"Надеюсь ты не станешь утверждать..."
Нет, не стану. Событие генерируется объектом VCL в ответ на получение Windows-сообщения CM_SOCKETMESSAGE от гнезда - объекта ОС.
>>"нитка, создавшая экземпляр TClientSocket "спит" и не обрабатывает сообщения ..."
А где ты видишь, что кто-то где-то шлет сообщения этой нитке ? Нет этого ни в коде автора ни в коде scktcomp.pas. Сообщения гнезда - объекта ОС посылаются в ОКНО, создаваемое объектом ClientWinSocket при активации ClientSocket, а Win32 автоматически вызывает оконную ф-ции этого окна.
Donal_Graeme (2002-04-11 15:52:00) [23]блин... и в nonBlocking тоже работает... ничего не менял...
может, более ранними тестами намусорил в памяти и поэтому не работало.
Donal_Graeme (2002-04-11 15:50:00) [24]интересно, поставил тип ctBlocking - работает. в смысле, коннектится.
Donal_Graeme (2002-04-11 15:43:00) [25]2 Digitman :
там тоже ставил. останов получил только в OnError на неправильный хост.
2 Reindeer Moss Eater :
но я же ловлю событие OnError, и выполняя там SetEvent нормально вываливаюсь из WaitForSingleObject
Reindeer Moss Eater (2002-04-11 15:34:00) [26]>Donal_Graeme
Попробуй сделать WaitForSingleObject в основном потоке и убедишься что событий никаких тоже не будет.
Digitman (2002-04-11 15:30:00) [27]>Donal_Graeme
Точку останова следовало ставить в теле OnConnect и OnError. Вот если и там не "ловится", тогда будем уточнять окружение всего того, от чего зависит поток
Reindeer Moss Eater (2002-04-11 15:24:00) [28]Надеюсь ты не станешь утверждать что СОБЫТИЕ в классе TClientSocket, в обработчике которого автор вопроса устанавливает Event для функции ожидания генерируется ОС.
Я утверждаю что событие не генерится из-за того, что нитка, создавшая экземпляр TClientSocket "спит" и не обрабатывает сообщения (waitforsingleobject)
Donal_Graeme (2002-04-11 15:22:00) [29]2 Digitman :
> Почему ты так уверен, что 5 секунд достаточно для работы
> запроса к DNS и установления соединения ?
ну, ессно, я не знаю, сколько времени нужно, но при тестировании потока я коннектился на себя, т.е. вправе ожидать почти немедленного ответа (что и происходит, если я соединяюсь не в потоке, а в программе).
насчёт того, действительно ли WaitForSingleObject ждёт заданное время - у меня там было и 50 секунд - висело ровно столько. Ещё я ставил точку останова на Wait и после - сразу вываливается только в случае неправильного хоста.
насчёт концептуальней правильно - это точно :-) переделаю.
Digitman (2002-04-11 15:18:00) [30]>Reindeer Moss Eater
ИМЕННО в данном случае класс TClientSocket инкапсулирует ф-ции управления ИМЕННО гнезда как объекта ОС. И ИМЕННО гнездо как объект ОС позволяет выбирать режим работы с ним как блокирующий (синхронный), так и неблокирующий (асинхронный). А вызывать ф-ции гнезда как объекта ОС можно в любом потоке, и никакой "синхронности" при этом не требуется.
Reindeer Moss Eater (2002-04-11 14:56:00) [31]Да мне безразлично Winsock API в этом конкретном случае.
Все что я говорил в этой ветке относится только к КЛАССАМ vcl и не более того.
Ты про асинхронный метод мне не ответил.
Digitman (2002-04-11 14:51:00) [32]А ты почитай дла начала описания WinsockAPI-ф-ций WSAAsyncSelect и WSAEventSelect ! Да посмотри, вызываются ли, как, в какой момент, в каких режимах и с какими параметрами хотя бы одна из этих ф-ций в реализации класса TClientSocket ! Тогда и поговорим)
Reindeer Moss Eater (2002-04-11 14:48:00) [33]> Donal_Graeme
если хочешь использовать сокет в потоке, то попробуй blocking режим и синхронные вызовы методов.
Reindeer Moss Eater (2002-04-11 14:44:00) [34]Все может быть.
Только объясни мне неверному такую вещь:
Если сокет использует nonblocking режим и вызов некого метода этого сокета асинхронный, то как реализовать этот метод внутри класса не используя потоки ?
Digitman (2002-04-11 14:34:00) [35]>Reindeer Moss Eater
Совершенно неверные у тебя представления о "потрохах" TClientSocket, работающем в режиме NonBlocking.
И "нитка внутри сокета" - выражение, лишенное смысла и логики.
Более того, ты "месишь в одну кучу" вещи совершенно разные, самостоятельные по сути и независящие друг от друга никак : "блокирующий режим работы" и "дополнительный кодовый поток"
Reindeer Moss Eater (2002-04-11 14:17:00) [36]>Digitman
Сокет у автора вопроса - nonblocking.
Значит где-то внутри класса создается поток.
Если в нем есть вызовы syncronize, то поток, создавший сам сокет должен продолжать обрабатывать очередь сообщений иначе нитка внутри сокета не будет выполнятся.
Digitman (2002-04-11 14:02:00) [37]>Reindeer Moss Eater
что это еще за "потоковый код сокета" ?
ты о событиях объекта TCustomWinSocket что ли ?
Reindeer Moss Eater (2002-04-11 13:41:00) [38]По моему нельзя морозить нить, создавшую сокет, если потоковый код сокета выполняется через syncronize.
Аналогичная ситуация у меня в ApdComPort из AsyncPro.
Digitman (2002-04-11 13:28:00) [39]1.
>>WaitForSingleObject (hEvent, 5000);// здесь ждёт сколько задано
Почему ты так уверен, что 5 секунд достаточно для работы запроса к DNS и установления соединения ?
Где анализ результата вызова WaitForSingleObject ? Он действительно "ждет" у тебя 5 сек ? Или возвращает управление сразу же после вызова ?
Концептуально правильней было бы реализовать участок ожидания сигнала события объекта hEvent в цикле, например, так :
MaxTimeOut: Dword; // поле, хранящее неизменяемый в процессе работы потока параметр макс.тайм-аута ожидания в цикле событий; параметр передается в конструкторе потока и может принимать значения либо INFINITE (ждать до бесконечности, пока либо соединение будет установлено, либо просигналит событие OnError()) либо заданное значение в м/сек, например, 60000
const
CyclicTimeOut = 1000; //тайм-аут для ф-ции ожидания
ActualTimeOut: DWord; //аккумулятор
...
ActualTimeOut := 0;
while not Terminated do
case WaitForSingleObject (hEvent, CyclicTimeOut) of// ждём недолго, чтобы оперативней реагировать на флаг Terminated
WAIT_OBJECT_0: break; // hEvent просигналил
WAIT_TIMEOUT:
begin
Inc(ActualTimeOut, CyclicTimeOut);//на всякий случай ведем сч-к времени ожидания, мало ли где он может понадобиться
if (MaxTimeOut <> INFINITE) //если не бесконечное ожидание
and (ActualTimeOut >= MaxTimeOut) then begin //и заданный тайм-аут исчерпан
ExitCode := ...; // код возврата, фиксирующий завершение потока по тайм-ауту для потенц.анализа причин завершения потока запустившим его кодом
Terminate;//тайм-аут исчерпан, терминируем сами себя
end;
end;
end;
If Terminated then
Exit;
if FTCP.Active then .... //и т.д.
Donal_Graeme (2002-04-11 10:08:00) [40]
begin
FreeOnTerminate := False;
FTCP := TClientSocket.Create (nil);
FTCP.OnRead := TCPRead;
FTCP.OnConnect := TCPConnected;
FTCP.OnError := TCPError;
try
SC_ParseURL (URL, Proto, Host, Port, Path);//раскладываю урл на части
FTCP.Host := Host;
FTCP.Port := StrToInt (Port);
FTCP.ClientType := ctNonBlocking;
ResetEvent (hEvent);
FTCP.Open;
WaitForSingleObject (hEvent, 5000);// здесь ждёт сколько задано
If Terminated then Exit;
If FTCP.Active then // здесь Active = False в любом случае
begin
// по большому счёту этот кусок не важен, так как до него не доходит выполнение никогда
WaitHeaders := True;
Headers.Clear;
Output.Clear;
FTCP.Socket.SendText("GET " +"/" +Path +"HTTP/1.0"#13#10#13#10);
Repeat
Until Terminated;
end;
finally
FTCP.Close;
FTCP.Free;
end;
end;
FTCPError и FTCPConnected : SetEvent (hEvent);