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

Вниз

TClientSocket в TThread не работает...   Найти похожие ветки 

 
Donal_Graeme   (2002-04-10 18:09) [0]

ничего не понимаю...
в главной форме работает, внутри метода потока Execute - не работает. один и тот же код :

FTCP.Host := Host;
FTCP.Port := StrToInt (Port);
FTCP.ClientType := ctNonBlocking;
FTCP.Open;

если в потоке, то работает так:
если Host задать неправильно, то он вываливается с ошибкой, т.е. работает, а если Host задан правильно, то коннекта не происходит и ошибок тоже не возникает.
хотя в основной программе коннектится и нормально работает.


 
Digitman   (2002-04-10 18:20) [1]

приведи весь код метода Execute


 
Donal_Graeme   (2002-04-11 10:08) [2]


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


 
Digitman   (2002-04-11 13:28) [3]

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 .... //и т.д.


 
Reindeer Moss Eater   (2002-04-11 13:41) [4]

По моему нельзя морозить нить, создавшую сокет, если потоковый код сокета выполняется через syncronize.
Аналогичная ситуация у меня в ApdComPort из AsyncPro.


 
Digitman   (2002-04-11 14:02) [5]

>Reindeer Moss Eater
что это еще за "потоковый код сокета" ?
ты о событиях объекта TCustomWinSocket что ли ?


 
Reindeer Moss Eater   (2002-04-11 14:17) [6]

>Digitman
Сокет у автора вопроса - nonblocking.
Значит где-то внутри класса создается поток.
Если в нем есть вызовы syncronize, то поток, создавший сам сокет должен продолжать обрабатывать очередь сообщений иначе нитка внутри сокета не будет выполнятся.


 
Digitman   (2002-04-11 14:34) [7]

>Reindeer Moss Eater
Совершенно неверные у тебя представления о "потрохах" TClientSocket, работающем в режиме NonBlocking.
И "нитка внутри сокета" - выражение, лишенное смысла и логики.

Более того, ты "месишь в одну кучу" вещи совершенно разные, самостоятельные по сути и независящие друг от друга никак : "блокирующий режим работы" и "дополнительный кодовый поток"


 
Reindeer Moss Eater   (2002-04-11 14:44) [8]

Все может быть.
Только объясни мне неверному такую вещь:
Если сокет использует nonblocking режим и вызов некого метода этого сокета асинхронный, то как реализовать этот метод внутри класса не используя потоки ?


 
Reindeer Moss Eater   (2002-04-11 14:48) [9]

> Donal_Graeme
если хочешь использовать сокет в потоке, то попробуй blocking режим и синхронные вызовы методов.


 
Digitman   (2002-04-11 14:51) [10]

А ты почитай дла начала описания WinsockAPI-ф-ций WSAAsyncSelect и WSAEventSelect ! Да посмотри, вызываются ли, как, в какой момент, в каких режимах и с какими параметрами хотя бы одна из этих ф-ций в реализации класса TClientSocket ! Тогда и поговорим)


 
Reindeer Moss Eater   (2002-04-11 14:56) [11]

Да мне безразлично Winsock API в этом конкретном случае.
Все что я говорил в этой ветке относится только к КЛАССАМ vcl и не более того.

Ты про асинхронный метод мне не ответил.


 
Digitman   (2002-04-11 15:18) [12]

>Reindeer Moss Eater

ИМЕННО в данном случае класс TClientSocket инкапсулирует ф-ции управления ИМЕННО гнезда как объекта ОС. И ИМЕННО гнездо как объект ОС позволяет выбирать режим работы с ним как блокирующий (синхронный), так и неблокирующий (асинхронный). А вызывать ф-ции гнезда как объекта ОС можно в любом потоке, и никакой "синхронности" при этом не требуется.


 
Donal_Graeme   (2002-04-11 15:22) [13]

2 Digitman :

> Почему ты так уверен, что 5 секунд достаточно для работы
> запроса к DNS и установления соединения ?

ну, ессно, я не знаю, сколько времени нужно, но при тестировании потока я коннектился на себя, т.е. вправе ожидать почти немедленного ответа (что и происходит, если я соединяюсь не в потоке, а в программе).

насчёт того, действительно ли WaitForSingleObject ждёт заданное время - у меня там было и 50 секунд - висело ровно столько. Ещё я ставил точку останова на Wait и после - сразу вываливается только в случае неправильного хоста.

насчёт концептуальней правильно - это точно :-) переделаю.


 
Reindeer Moss Eater   (2002-04-11 15:24) [14]

Надеюсь ты не станешь утверждать что СОБЫТИЕ в классе TClientSocket, в обработчике которого автор вопроса устанавливает Event для функции ожидания генерируется ОС.

Я утверждаю что событие не генерится из-за того, что нитка, создавшая экземпляр TClientSocket "спит" и не обрабатывает сообщения (waitforsingleobject)


 
Digitman   (2002-04-11 15:30) [15]

>Donal_Graeme
Точку останова следовало ставить в теле OnConnect и OnError. Вот если и там не "ловится", тогда будем уточнять окружение всего того, от чего зависит поток


 
Reindeer Moss Eater   (2002-04-11 15:34) [16]

>Donal_Graeme
Попробуй сделать WaitForSingleObject в основном потоке и убедишься что событий никаких тоже не будет.


 
Donal_Graeme   (2002-04-11 15:43) [17]

2 Digitman :

там тоже ставил. останов получил только в OnError на неправильный хост.

2 Reindeer Moss Eater :

но я же ловлю событие OnError, и выполняя там SetEvent нормально вываливаюсь из WaitForSingleObject


 
Donal_Graeme   (2002-04-11 15:50) [18]

интересно, поставил тип ctBlocking - работает. в смысле, коннектится.


 
Donal_Graeme   (2002-04-11 15:52) [19]

блин... и в nonBlocking тоже работает... ничего не менял...
может, более ранними тестами намусорил в памяти и поэтому не работало.


 
Digitman   (2002-04-11 15:53) [20]

>Reindeer Moss Eater
>>"Надеюсь ты не станешь утверждать..."
Нет, не стану. Событие генерируется объектом VCL в ответ на получение Windows-сообщения CM_SOCKETMESSAGE от гнезда - объекта ОС.

>>"нитка, создавшая экземпляр TClientSocket "спит" и не обрабатывает сообщения ..."

А где ты видишь, что кто-то где-то шлет сообщения этой нитке ? Нет этого ни в коде автора ни в коде scktcomp.pas. Сообщения гнезда - объекта ОС посылаются в ОКНО, создаваемое объектом ClientWinSocket при активации ClientSocket, а Win32 автоматически вызывает оконную ф-ции этого окна.


 
Donal_Graeme   (2002-04-11 15:53) [21]

извиняюсь за сумбур :-))

в ctBlocking работает, в ctNonBlocking - не работает


 
Reindeer Moss Eater   (2002-04-11 15:55) [22]

> Donal_Graeme
Я не изучал код класа TClientSocket, но могу предположить что событие OnError генерится не внутри потока, создаваемого в классе сокета.
Но если режим асинхронный, то событие OnConnect генерится именно из этого потока (не может по другому быть).
А раз поток, создавний экземпляр TClientSocket "спит", то сообщения того "внутреннего" потока (который так не понравился Digitman"у) просто некому обрабатывать.
Вот и все.
Выход простой: либо жди event в цикле со слипами, либо используй синхронный режим.
Асинронный режим удобен именно в основном потоке приложения, а в доплнительных потоках от него никакого толку нет.


 
Reindeer Moss Eater   (2002-04-11 15:58) [23]

ctBlocking работает патаму что не использует поток внутри класса.


 
Reindeer Moss Eater   (2002-04-11 16:02) [24]

> Digitman
Попробуй в основном потоке сделать Waitforsingleobject и после этого посмотри как Win32 будет "автоматически вызывать оконную функцию"


 
Digitman   (2002-04-11 16:07) [25]

>Reindeer Moss Eater
Нет никаких "внутренних потоков" у гнезда - объекта ОС.
Как нет их и в гнезде - объекте VCL класса TClientSocket ни в ctBlocking- ни в ctNonBlocking-режиме.


 
Donal_Graeme   (2002-04-11 16:08) [26]

я попробовал... точно, врежиме nonBlocking в основном потоке OnConnect тоже не ловится.


 
Donal_Graeme   (2002-04-11 16:11) [27]

я имею ввиду - если использовать WaitForSingleObject


 
Reindeer Moss Eater   (2002-04-11 16:14) [28]

>Digitman
Повторю еще раз, что я здесь говорил про КЛАССЫ VCL
И класc TClientSocket(как и любой другой класс) если у него есть АСИНХРОННЫЙ метод
НЕ МОЖЕТ НЕ ИМЕТЬ внутри себя "внутренних потоков"



 
Digitman   (2002-04-11 16:25) [29]

>Reindeer Moss Eater
Есть очередь сообщений окну, а есть очередь сообщений потоку (дополнительному). Две совершенно разные очереди, с т.з. ОС и API-вызовов, позволяющих реагировать на эти сообщения


 
Reindeer Moss Eater   (2002-04-11 16:31) [30]

>Digitman
И это тоже может быть.
Только многопоточность в Delphi реализована таким образом, что код вторичного потока в конечном итоге все равно выполняется в основном потоке.
И если в последнем вызвана функция ожидания, то вторичный поток тоже стоит на месте.
Я был когда-то сильно опечален, поняв это.


 
Digitman   (2002-04-11 17:16) [31]

>Reindeer Moss Eater
Утверждение твое неверно. Совершенно неверно. Кодовые потоки в контексте одного процесса абсолютно независимы друг от друга и выполняются "параллельно". Иначе бы понятия "синхронизация потоков" и "объекты синхронизации" попросту были бы лишены всякого смысла применительно к рассматриваемой нами ситуации.

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


 
Reindeer Moss Eater   (2002-04-11 17:43) [32]

Я конечно же был неточен, согласен.
Но если вторичный поток использует syncronize, или делает Sendmessage вызвавшему потоку, то получится как раз то, что я и имел ввиду


 
Digitman   (2002-04-11 18:38) [33]

>Reindeer Moss Eater

Вызов Sendmessage() предназначен для синхронной посылки сообщения не потоку, а окну.

Доп.поток у автора нигде не вызывает Synchronize() - ни явно ни неявно.


 
Reindeer Moss Eater   (2002-04-11 18:47) [34]

>Digitman
Если помнишь, я сказал, что проблема автора не в его коде, а в реализации асинхронного метода в классе TClientSocket.
Если поток, создавший экземпляр TClientSocket спит, то экземпляр TClientSocket не генерирует события OnConnect.
Автор проверил это в основном потоке и уже сказал, что не работает не только в дополнительной нитке, но и в основной, если в ней вызвать функцию ожидания.



 
Digitman   (2002-04-12 08:38) [35]

>Reindeer Moss Eater
Ты уже близок к истине)
Вот смотри. Дело не в том, что поток "спит", а в том, что в "спать" ему в дан.случае следует чуть по-другому. Доработаем немного цикл ожидания и заставим доп.поток "спать чутко", реагируя на оконные события:


var
Msg: TMsg;
...
PeekMessage(Msg, 0, WM_USER, WM_USER, PM_NOREMOVE);//первая строчка в Execute()
...
while not Terminated do
case MsgWaitForMultipleObjects (1, hEvent, False, CyclicTimeOut, QS_ALLINPUT) of
WAIT_OBJECT_0: break; // hEvent просигналил
WAIT_TIMEOUT:
begin
Inc(ActualTimeOut, CyclicTimeOut);
if (MaxTimeOut <> INFINITE)
and (ActualTimeOut >= MaxTimeOut) then begin
ExitCode := ...;
Terminate;
end;
end;
WAIT_OBJECT_0 + 1:
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
if Msg.hWnd = 0 then
Dispatch(Msg.Message)
else
DispatchMessage(Msg);
end;
...



 
Reindeer Moss Eater   (2002-04-12 08:48) [36]

Признаю, что вчера был неправ насчет вторичных потоков в TClientSocket.
Их действительно нет.
Вся реализация асинхронных методов находится внутри winsock.dll
Если режим работы асинхронный, то класс просто сообщает что хочет выполнить метод асинхронно и передает дескриптор окна, которому winsock.dll должна будет отправить сообщение по окончании метода.
После чего генерится событие внутри класса.
Но так как нитка спит, то сообщение не обрабатывается.


 
Donal_Graeme   (2002-04-12 09:57) [37]

а почему тогда OnError обрабатывается?
в чём разница между OnError и OnConnect?


 
Reindeer Moss Eater   (2002-04-12 10:11) [38]

Видимо потому что это событие генерится до возврата из метода DoOpen.
Иными словами до вызова функции ожидания


 
Digitman   (2002-04-12 10:36) [39]

>Donal_Graeme
Использование TClientSocket в режиме ctNonBlocking в доп.потоке является концептуально неправильным решением. Хотя и можно добиться корректной работы гнезда при таком подходе (см. выше примеры с уточнениями), все же лучше в твоем случае работать в режиме ctBlocking.


 
Donal_Graeme   (2002-04-12 14:47) [40]

кажется, понял :-) большое спасибо за помощь



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

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

Наверх





Память: 0.56 MB
Время: 0.006 c
8-88965
[NIKEL]
2002-02-16 16:13
2002.06.27
Можно ли разбить BMP так


14-89035
AZ
2002-05-24 07:05
2002.06.27
М.С. Норбеков. «Опыт дурака … как избавиться от очков»


3-88696
sergikkkk
2002-06-01 11:50
2002.06.27
interbase


3-88704
Slym
2002-06-03 07:11
2002.06.27
Имеются 3 связанные по цепочке по MasterSource таблицы


3-88735
Jaroshik
2002-06-04 10:58
2002.06.27
Отчеты QuickReport





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский