Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Винет поток на функции Socket(). [D7, WinXP]


Страницы:   1 2

DVM ©   (2007-06-04 11:02:00) 

Ситуация такая:

Есть кнопка, при нажатии на которую создается поток, выполняющий HTTP запрос и самоликвидирующийся после выполнения. Все вобщем работает нормально, если кнопку нажимать не очень часто. Если кнопку нажимать очень часто, то спустя некоторое время (100-150 нажатий), потоки продолжают создаваться, но уже не завершаются, т.к. виснут на вызове функции Socket(). В чем может быть проблема?
Вторичные потоки никак не взаиможействуют с главным после запуска, все параметры передаются в них при старте. Друг с другом тоже не взаимодействуют.


DVM   (2007-06-04 13:42:00) [21]


> Есть же неблок.режим с асинхронными нотификациями

Я привык к блокирущим сокетам. Неблокирующий режим немного недолюбливаю и потому не использую без особой нужды. Хотя, наверное, я не прав.


Сергей М.   (2007-06-04 13:35:00) [22]


> подумал, зачем так часто опрашивать select()


А действительно, зачем опрашивать вообще?

Есть же неблок.режим с асинхронными нотификациями (WSAAsyncSelect, WSAEventSelect) ..


DVM   (2007-06-04 13:25:00) [23]


> Странная у тебя методика отладки) ...
>
> Дилетантством отлает .. А вроде бы ты и не новичок, чтобы
> бипами контролировать работу своего кода ..

Да я не всегда бипами. Просто так оно быстрее писать иногда, а эффект тот же. :) Если бип прошел или не прошел, тогда уж по обстоятельствам смотрю. Может это и дилетантство.


DVM   (2007-06-04 13:22:00) [24]


> Если торопишься, то зачем тогда delay(50) ? Это же лишняя
> бестолковая задержка !

Может и лишняя строка, у меня у самого сомнения были на счет нее. Просто подумал, зачем так часто опрашивать select() - грузить систему. 50 мсек - это же совсем мало.


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

Допустим я посылаю запрос узлу 192.168.0.20, собственный адрес 192.168.0.10 - connect() блокирует поток на 20 секунд где то. Попробуйте сами - положите на форму компонент от инди и кнопку и выполните запрос:


IdHTTP1.Get(' http://192.168.0.21');


Если узла такого нет, то у меня блокировка на 20 секунд возникает


Сергей М.   (2007-06-04 13:18:00) [25]


> пробовал вчера делать так:
>
> try
> FSock := SocketConnect();
> except
>  Windows.Beep(...);
> end;


Странная у тебя методика отладки) ...

Дилетантством отлает .. А вроде бы ты и не новичок, чтобы бипами контролировать работу своего кода ..


Сергей М.   (2007-06-04 13:16:00) [26]


> А это долго (секунд 10-15)


А ты куда-то торопишься ?

Если торопишься, то зачем тогда delay(50) ? Это же лишняя бестолковая задержка !


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


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


DVM   (2007-06-04 13:14:00) [27]

Кстати, по поводу


> ..
> try
>  FSock := SocketConnect();
> except
>  on e: Exception do begin
>    MessageBox(0, PChar(e.Classname + ' ' + e.Message), '',
>  MB_OK or MB_SETFOREGROUND);
>    raise;
>  end;
> end;
> ..

:

Я пробовал вчера делать так:

try
FSock := SocketConnect();
except
 Windows.Beep(...);
end;

Тишина была.


DVM   (2007-06-04 13:08:00) [28]


> 1. Зачем вызывать SocketDisconnect() безусловно, если предшествующий
> SocketConnect() может вернуть отказ ?

Согласен


> 2. Зачем возвращать гнездо в блок.режим перед его закрытием
> ?

Согласен, правда этого куска раньше не было, я в поисках ошибки вставил его и потом забыл.


> 3. Зачем нужен неблокирующий коннект, если все остальные
> операции с гнездом  - блокирующие ?

А вот зачем. Если поток висит на Connect() в случае блокирующих сокетов (например когда узел недоступен), то завершение такого потока невозможно до того как выйдет таймаут. А это долго (секунд 10-15). Чтобы быстро прервать Connect() я и превожу сокеты в неблокирующий режим. Далее работаю с блокирующими, т.к. это проще.


Сергей М.   (2007-06-04 12:59:00) [29]

1. Зачем вызывать SocketDisconnect() безусловно, если предшествующий SocketConnect() может вернуть отказ ?

2. Зачем возвращать гнездо в блок.режим перед его закрытием ?

3. Зачем нужен неблокирующий коннект, если все остальные операции с гнездом  - блокирующие ?


DVM   (2007-06-04 12:42:00) [30]


> Сергей М. ©   (04.06.07 12:29) [8]

Странно, но даже с моим кодом описанный эффект пропал на другом компьютере. Проявлялся ранее на домашнем компьютере, на рабочем не могу добиться того же. Тогда дома попробую.


> Куча серьезных замечаний по коду.

Каких?


Сергей М.   (2007-06-04 12:29:00) [31]

Куча серьезных замечаний по коду.

Ну да это не столь важно пока.

Пробуй вот такой код:

..
try
 FSock := SocketConnect();
except
 on e: Exception do begin
   MessageBox(0, PChar(e.Classname + ' ' + e.Message), '', MB_OK or MB_SETFOREGROUND);
   raise;
 end;
end;
..

Изменения в поведении программы при этом наблюдаются ?


DVM   (2007-06-04 12:16:00) [32]


> Какой резон использовать VCL (хотя бы в части задействования
> класса TThread), если работа с Winsock организована непосредственно
> на WinsockAPI ?

Да собственно, особенного резона, конечно нет. С оберткой немного удобнее.


> Как определил ?

Элементарно поставил Windows.Beep(500,50); сначала до, потом после строки этой (Socket()) - до всегда пикает, после с некоторого момента пикать перестает.


> Приводи код TThread ..


Это метод Execute:


procedure TCommandThread.Execute;
var
 Wsa: TWSADATA;
 WsaErr: integer;
 Res: integer;
begin
 FreeOnTerminate := true;
 WsaErr := WSAStartUp($0101, Wsa);
 try
   if WsaErr = 0 then
     begin
       Init;
       FSock := SocketConnect();
       try
         if FSock <> -1 then
           begin
             Res := SendRequest(FSock, FRequest);
             if Res = 0 then ReadData(FBuffer, 0);
           end
       finally
         SocketDisconnect();
       end;
     end;
 finally
   WSACleanUp;
 end;
end;


Это то место где коннект:


function TCommandThread.SocketConnect: integer;
var
 Len: integer;
 Block: Cardinal;
 Wfd: TFDSet;
 TimeVal: TTimeVal;
 BeginConnectTime: Cardinal;
begin  
 Result := socket(AF_INET, SOCK_STREAM, 0);

 if Result = INVALID_SOCKET then
   begin
     Result := -1;  
     exit;
   end;

 Block := 1;
 if ioctlsocket(Result, FIONBIO, Block) = SOCKET_ERROR then
   begin
     CloseSocket(Result);
     Result := -1;
     exit;
   end;

 Len := SizeOf(FAddr);
 TimeVal.tv_sec := 0;
 TimeVal.tv_usec := 100;
 FD_ZERO(wfd);
 FD_SET(result, wfd);

 if Connect(Result, @FAddr, Len) = SOCKET_ERROR then
   begin
     
     if WSAGetLastError =  WSAEWOULDBLOCK then
       begin
         BeginConnectTime := GetTickCount;
         while (not Terminated) and ((GetTickCount - BeginConnectTime) <= 5000) do
           begin
             case select(Result, nil, @wfd, nil, @TimeVal) of
               0:
                 begin
                   FD_ZERO(wfd);
                   FD_SET(result, wfd);
                   delay(50);
                 end;
               1:
                 if FD_ISSET(Result, wfd) then break;
               SOCKET_ERROR:
                 begin
                   Block := 0;
                   ioctlsocket(Result, FIONBIO, Block);
                   CloseSocket(Result);
                   Result := -1;
                 end;
             end;
             
           end
        end
      else
        begin
          CloseSocket(Result);
          Result := -1;
        end;
   end;

 Block := 0;
 if ioctlsocket(Result, FIONBIO, Block) = SOCKET_ERROR then
   begin
     CloseSocket(Result);
     Result := -1;
     exit;
   end;
end;


Сергей М.   (2007-06-04 12:07:00) [33]


> используется именно TThread


Какой резон использовать VCL (хотя бы в части задействования класса TThread), если работа с Winsock организована непосредственно на WinsockAPI ?

Поясни ..


> выполнение останавливается на Socket


Как определил ?

Приводи код TThread ..


DVM   (2007-06-04 12:02:00) [34]


> Подозреваю, что речь не идет о TThread.

Нет здесь используется именно TThread c флагом FreeOnTerminate=true

Но дело не в потоке. Его выполнение останавливается на Socket()


Сергей М.   (2007-06-04 11:46:00) [35]


> SpellCaster   (04.06.07 11:40) [2]


А причем здесь это ?

Подозреваю, что речь не идет о TThread.

А в этом случае автор должен сам позаботиться о закрытии хэндлов.


clickmaker   (2007-06-04 11:42:00) [36]


> [2] SpellCaster   (04.06.07 11:40)

procedure TThread.Terminate;
begin
 FTerminated := True;
end;

;)


SpellCaster   (2007-06-04 11:40:00) [37]

> Поток не может "самоликвидироваться".

А как же вызов Terminate в методе Execute с FreeOnTerminate=False?


Сергей М.   (2007-06-04 11:21:00) [38]


> поток..самоликвидирующийся после выполнения


Поток не может "самоликвидироваться".

"Ликвидация" объекта-нити  - это закрытие всех хэндлов, ассоциированных с этим объектом.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо