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

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

CloseSocket() в неблокирующем режиме. Вопрос. [D7, WinXP]


DVM ©   (2006-09-26 11:25:00) 

Сокет находится в неблокирующем режиме. Я закрываю сокет функцией CloseSocket(). Вопрос - как мне с гарантией удостовериться, что сокет закрылся. Следом за сокетом мне надо уничтожить поток, в котором сокет используется, но я опасаюсь как бы поток не завершился раньше того как система выполнит всю работу по закрытию сокета. Иначе AV.


Сергей М.   (2006-09-26 21:04:00) [1]


> В справке для KAV 6 так и написано


"Упалпацтул"(С) славарь падонкафф


DVM   (2006-09-26 17:53:00) [2]

И то что я написал в [11] - это же явный баг.


DVM   (2006-09-26 17:52:00) [3]


> При чем здесь антивирь Кашмарского ?)
> Ты со своей логикой разберись) ...

Я же написал "попутно". Со своей логикой разбираюсь. Кроме того, некоторые проблемы с работой моей логики по всей видимости все-таки связаны с данным антивирусом. Проблемы причем не только у меня. Проблемы у многих программ, принимающих потоковые данные типа видео, звука и т.д. В справке для KAV 6 так и написано.


Сергей М.   (2006-09-26 16:10:00) [4]


> DVM ©   (26.09.06 15:33) [11]


При чем здесь антивирь Кашмарского ?)
Ты со своей логикой разберись) ...


DVM   (2006-09-26 15:33:00) [5]

Попутно обнаружил крайне странную вещь! Оказывается KAV 6.0 при включенном анализе HTTP трафика портит данные на выходе. Т.е. они отличаются от того, что на входе.

Если в ответе HTTP сервера приходящем ко мне должно быть изначально #13#10#13#10 - конец заголовка ответа сервера, то после прохождения через касперского получается #13#10#13#10#10#10.

Нет слов!


Сергей М.   (2006-09-26 12:28:00) [6]


> хочется обойтись обычными


Тогда таймаут делай насколько возможно малым.
Это позволит потоку оперативно реагировать на флаг Terminated


> надо дождаться появления ошибки


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


DVM   (2006-09-26 12:18:00) [7]


> Почему ?

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

Насчет асинхронных Windows сокетов я подумаю, но, честно говоря, хочется обойтись обычными.


Сергей М.   (2006-09-26 12:09:00) [8]


> поток закрывается теперь медленнее 2-3 секунды


Вместо connect+select используй WSAAsyncSelect/WSAEventSelect + WSAConnect, тогда твой поток сможет оперативно реагировать и на событие коннекта и на сигналы синхронизации, посылаемые потоку в качестве команды "закругляться немедленно"


Сергей М.   (2006-09-26 12:09:00) [9]


> Строку выявить пока не получается


Почему ?


DVM   (2006-09-26 12:07:00) [10]


> Приведенное тело метода SocketConnect не может вызвать AV
> - исключение возникает где-то за его пределами. Точнее -
>  на строчке кода, адрес XXXXXXXX которого фигурирует в сообщении
> об исключении "Access violation at address XXXXXXXX ...".
>

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

> Ну и явная несуразность здесь присутствует:

Да, действительно, не заметил.


Сергей М.   (2006-09-26 12:03:00) [11]

Приведенное тело метода SocketConnect не может вызвать AV - исключение возникает где-то за его пределами. Точнее - на строчке кода, адрес XXXXXXXX которого фигурирует в сообщении об исключении "Access violation at address XXXXXXXX...".

Ну и явная несуразность здесь присутствует:

if Result <> INVALID_SOCKET then
... //гнездо успешно создано
else
  //гнездо не создано
  begin
    CloseSocket(Result); //закрывать-то при этом нечего - гнездо же не создано !
    Result := -1;
  end;
end;


DVM   (2006-09-26 11:56:00) [12]

Так же, наверное, замечу, что обращение к FThread.Sock в объекте потока сделано так:

function THTTPThread.GetSock: integer;
begin
 FCriticalSection.Enter;
 try
   Result := FSock;
 finally
   FCriticalSection.Leave;
 end;
end;


DVM   (2006-09-26 11:51:00) [13]

Если изменить так:

if FThread <> nil then
  begin
    ///// CloseSocket(FThread.Sock);
    FThread.Terminate;
    FThread.WaitFor;
    FThread.Free;
    FThread := nil;
  end;

То вроде работает нормально. (Сижу тестирую). Но поток закрывается теперь медленнее 2-3 секунды. Раньше почти мгновеннно.


DVM   (2006-09-26 11:47:00) [14]


> Приведи код, в котором ты получаешь AV после CloseSocket().
> .

Он очень большой, но постараюсь описать подробнее.

Поток делает коннект примерно следующим образом:

function THTTPThread.SocketConnect: integer;
var
 Len, Res: integer;
 Block: Cardinal;
 rfd, wfd: TFDSet;
 FTimeout2: TTimeVal;
begin
 Result := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 if Result <> INVALID_SOCKET then
   begin
     Block := 1;
     ioctlsocket(Result, FIONBIO, Block);
     Len := SizeOf(FAddr);
     Res := Connect(Result, @FAddr, Len);
     FD_ZERO(rfd);
     FD_ZERO(wfd);
     FTimeout2.tv_sec := 2;
     FTimeout2.tv_usec := 0;
     while not terminated do
       begin
         FD_SET(result, rfd);
         FD_SET(result, wfd);
         case select(0, @rfd, @wfd, nil, @FTimeOut2) of
           -1: begin
                 CloseSocket(Result);
                 Result := -1;
               end;
            0: sleep(5);
         else
           begin
             Block := 0;
             ioctlsocket(Result, FIONBIO, Block);
             break;
           end;  
         end;
       end;
   end
 else
   begin
     CloseSocket(Result);
     Result := -1;
   end;
end;

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

В основном потоке программы я закрываю соединение и вторичный поток так:

 if FThread <> nil then
   begin
     CloseSocket(FThread.Sock);
     FThread.Terminate;
     FThread.WaitFor;
     FThread.Free;
     FThread := nil;
   end;

Вот я и подумал, а вдруг на момент закрытия сокета он находится в неблокирующем режиме и CloseSocket вернет управление сразу. А далее поток умрет быстрее чем система сокет закроет.

Подмечено, что AV возникает при включенном антивирусе касперского 6 чаще всего. Без него очень очень редко.


Сергей М.   (2006-09-26 11:35:00) [15]


> Иначе AV


Приведи код, в котором ты получаешь AV после CloseSocket()..


Наверх

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