На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Соблюдайте общие правила форума
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Указывайте точные версии Delphi и используемых сетевых библиотек.

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

Внимание:
попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Krid, user posted image Rouse_

Модераторы: Krid, Rouse_
  
> Timeout подключения TClientSocket
    Здравствуйте!
    TClientSocket в блокирующем режиме при подключении к хосту, который не работает, - довольно долго ждёт, перед тем как выбросить исключение. Можно ли сделать так, чтобы он ждал поменьше?
      Цитата Nagva27 @
      блокирующем режиме при подключении к хосту, который не работает, - довольно долго ждёт

      Это совершенно нормальное состояние блокирующего сокета. У функции connect(), которая осуществляет хендшейк, есть внутренний таймаут, величина которого в разных ОС - разная. Например в BSD это 75 секунд, в некоторых Виндах - 45 секунд и тд.
      Вмешаться в этот процесс в дельфях довольно непросто, но возможно.
      Сообщение отредактировано: Oleg2004 -
        Цитата Oleg2004 @
        Вмешаться в этот процесс в дельфях довольно непросто, но возможно.

        1. Перевести в неблок
        2. Цикл проверки состояния через select + sleep на маленький интервал перед следующей итерацией
        3. При превышении общего времени ожидания - выход по таймауту
        4. Перевести обратно в блок
        5. ???
        6. PROFIT!
          Цитата Fr0sT @
          1. Перевести в неблок
          2. Цикл проверки состояния через select + sleep на маленький интервал перед следующей итерацией
          3. При превышении общего времени ожидания - выход по таймауту
          4. Перевести обратно в блок
          5. ???
          6. PROFIT!

          Вы невластны над внутреним таймаутом функции connect(). :)
          Время посылки повторного сегмента S для RTO рассчитывается по специальной формуле в зависимости от RTT.
          И если даже вы сделаете все как вы пишите в общем то правильно, прекратить исполнение connect() вы не сможете.
          Да, вы сможете вернуться в основную программу по таймауту select(), но connect() все равно будет пытаться соединиться - потому как поставлена в неблокирующее состояние. В винде специально раньше использовалась функция WSACancelBlockingCall() - для этой цели.
          Сообщение отредактировано: Oleg2004 -
            Oleg2004, так и что же можно сделать?
            Сообщение отредактировано: Nagva27 -
              Основная идея исполнения асинхронных функций в Виндовсе типа например WSAAsyncGetHostByName() заключается в том что просто выполняется тот же самый стандартный GetHostByName() - но он выполняется в ОТДЕЛЬНОМ потоке. А вот поток может быть остановлен из главного потока - TerminateThread(). Это основной способ в винде прервать исполнение асинхронной функции. Так что идея в общем то проста - надо исполнять неблокирующий коннект в отдельном предназначенном для этого потоке и через select() (смотрите здесь к примеру) убивать этот поток вместе с функцией если не хотите долго ждать. Я бы лично это не приветствовал - такое поведение коннекта для него родное. Что делать, лучше подождать, когда сам коннект скажет - баста, не хочу.
              Сообщение отредактировано: Oleg2004 -
                Цитата Oleg2004 @
                Вы невластны над внутреним таймаутом функции connect()

                Зато я властен прибить его в любое время
                Цитата Oleg2004 @
                прекратить исполнение connect() вы не сможете

                Closesocket справится.
                Цитата Oleg2004 @
                Так что идея в общем то проста - надо исполнять неблокирующий коннект в отдельном предназначенном для этого потоке и через select() (смотрите здесь к примеру) убивать этот поток вместе с функцией если не хотите долго ждать.

                Какой-то странный набор букв. Зачем поток, если сокет и так неблокирующий? Зачем убивать поток, если есть корректный способ завершения? Зачем ждать, пока коннект соизволит отвалиться сам (таймаут в минуту - суровое испытание нервов юзера)?
                Короче, вот кусок моего класса
                ExpandedWrap disabled
                  const
                    WaitIntrv  = 50;   // [msec] wait for socket to be ready
                    SleepIntrv = 100;  // [msec] wait between state check attempts
                  ...
                  try
                    ...
                   
                    // Establish connection using non-blocking mode (to be able to respect specified Timeout )
                   
                    elapse := FTimeout;
                    if SleepIntrv < FTimeout
                      then currsleep := SleepIntrv
                      else currsleep := FTimeout;
                    OldBlocking := Blocking;
                    Blocking := False;
                    if WinSock.connect(FSckt, pAddr^, SizeOf(TSockAddr)) = SOCKET_ERROR then
                    begin
                      // connect error?
                      CheckWSResult(WSAGetLastError = WSAEWOULDBLOCK, 'connect');
                      // else - connect in process - repeat checking socket state
                      repeat
                        if elapse <= 0 then  // time is out
                        begin
                          WSASetLastError(WSAETIMEDOUT);
                          CheckWSResult(False, 'connect');
                        end;
                        FD_ZERO(Wfd);
                        FD_SET(FSckt, Wfd);
                        FD_ZERO(EFd);
                        FD_SET(FSckt, Efd);
                        TimeVal.tv_sec := 0;
                        TimeVal.tv_usec := WaitIntrv;
                        // check socket state
                        res := select(0, nil, @Wfd, @Efd, @TimeVal);
                        CheckWSResult(res <> SOCKET_ERROR, 'select');
                        case res of
                          // not ready - wait
                          0: begin Sleep(currsleep); Dec(elapse, currsleep); end;
                          // ready - check result
                          1: if FD_ISSET(FSckt, Efd) then             // error - get error code and exit
                             begin
                               Len := SizeOf(err);
                               if getsockopt(FSckt, SOL_SOCKET, SO_ERROR, @err, Len) = SOCKET_ERROR then
                                 err := WSAECONNREFUSED;
                               WSASetLastError(err);
                               CheckWSResult(False, 'connect');
                             end
                             else if FD_ISSET(FSckt, Wfd) then Break  // OK - finish the loop
                             else;
                          // smth else
                          else
                            CheckWSResult(False, 'select');
                        end; // case
                      until False;
                    end;
                    Blocking := OldBlocking;
                    FActive := True;
                    ...
                   
                    except   // error - close socket
                      err := WSAGetLastError;
                      Close;
                      WSASetLastError(err);
                      raise;
                    end;


                Добавлено
                Очевидно, на время ожидания таймаута основной поток "зависнет", что можно решить, размазав логику (напр., выполнять проверки по таймеру, естественно, уже без Sleep), либо вынеся сокет в отдельный тред, либо совсем кардинально - перейдя на асинхронную модель. Для числа одновременных коннектов <= 10 асинхронка - оверкилл, легче и проще задействовать треды. К тому же синхронку можно довольно легко реализовать самому на Winapi, а вот асинхронку лучше делать на испытанных библиотеках, поскольку режим имеет приличные подводные камни и просто глюки, и при создании собственного велосипеда нарываться на каждый из них будет неприятно.
                Сообщение отредактировано: Fr0sT -
                  Цитата Fr0sT @
                  Closesocket справится.

                  Интересная мысль :)
                  Так лучше программу прибить - крестик справа вверху.

                  Цитата Fr0sT @
                  Какой-то странный набор букв. Зачем поток, если сокет и так неблокирующий? Зачем убивать поток, если есть корректный способ завершения? Зачем ждать, пока коннект соизволит отвалиться сам (таймаут в минуту - суровое испытание нервов юзера)?

                  Какой-то странный набор букв. <_<
                  1. зачем поток. Объясняю, что такое так наз. "неблокирующий" сокет. Во первых, неблокирующих сокетов не существует. Сокеты так сокетами и остаются.
                  Неблокирующими становятся ФУНКЦИИ, которые в противном случае остановили бы исполнение программы на изрядное время.
                  2. Соглашусь, что в вашем коде вы контролируете время установления соединения, при этом ваш код "висит" на селекте. Но исполнение селекта в цикле - это уж слишком. По сути, как я понял (а это всегда нелегко - разбираться в чужом коде :) ) вы просто возвращаете управление в программу по истечении таймаута - но само исполнение коннекта, который теперь работает совершенно автономно - вы прекратить не можете.
                  Кроме как убить сокет.
                  Думаю что в таком случае в Винапи и была придумана функция WSACancelBlockingCall().
                  Тогда коннект исполняется как блокирующий в другом потоке.
                  Вот здесь есть кое-что, и что интересно - ни одного примера с коннектом. Потому как это неизбежно - время на рукопожатие.
                  3. В общем, заморачиваться по этому поводу :"таймаут в минуту - суровое испытание нервов юзера)?" - я не вижу абсолютно никакого смысла. Пусть юзверь понимает, что есть вещи, с которыми мы обязаны сосуществовать. :yes:
                  Сообщение отредактировано: Oleg2004 -
                    Nagva27
                    Можно пропинговать сервер и если нет ответа не выполнять соединение сокетом.
                      ^D^ima
                      Вы неправы. :)
                      Пинг лишь определяет что компутер включен в сеть и на нем функционирует стек TCP/IP
                      Отвечает модуль ICMP, который к никакому серверу не имеет отношения.
                      Сообщение отредактировано: Oleg2004 -
                        Цитата Oleg2004 @
                        Так лучше программу прибить - крестик справа вверху.

                        Цитата Oleg2004 @
                        Объясняю, что такое так наз. "неблокирующий" сокет. Во первых, неблокирующих сокетов не существует. Сокеты так сокетами и остаются.
                        Неблокирующими становятся ФУНКЦИИ, которые в противном случае остановили бы исполнение программы на изрядное время.

                        Передергивать и буквоедствовать — очень продуктивно, да.
                        "неблокирующий" сокет - в просторечии сокет в неблокирующем режиме.
                        Цитата Oleg2004 @
                        Так лучше программу прибить - крестик справа вверху.

                        Придирки не понял. Что ж, раз сокет коннектится - его теперь на трон королевский посадить и пылинки сдувать?
                        Цитата Oleg2004 @
                        2. Соглашусь, что в вашем коде вы контролируете время установления соединения, при этом ваш код "висит" на селекте.

                        "Висит", потому что так сделано. Это простейшая обертка над сокетом, в основном для блокирующего режима, но т.к. создатели библиотеки протупили и не сделали штатного средства регулирования таймаута - приходится делать вот такие кунштюки.
                        Цитата
                        Но исполнение селекта в цикле - это уж слишком.

                        Аргументы?
                        Цитата
                        По сути, как я понял (а это всегда нелегко - разбираться в чужом коде ) вы просто возвращаете управление в программу по истечении таймаута - но само исполнение коннекта, который теперь работает совершенно автономно - вы прекратить не можете.
                        Кроме как убить сокет.

                        А мне плевать на "исполнение коннекта" именно данного конкретного сокета. Что там происходит унутрях сетевого драйвера, какие хэндшейки и ожидания - меня никоим образом не заботит. Не прошел коннект за установленное время - прибиваем хэндл, и пусть система сама дочищает оставшиеся хвосты. В любом случае повлиять на этот процесс никто не может, т.ч. и думать про него нет смысла.
                        Цитата Oleg2004 @
                        Думаю что в таком случае в Винапи и была придумана функция WSACancelBlockingCall().

                        Не помешает почитать справку по этой функции
                        Цитата Oleg2004 @
                        Вот здесь есть кое-что

                        Ага, прекрасная подборка: "not working", "doesn't work", etc :lool:
                        Вообще вся эта система хуков на сокетах какой-то странный неуклюжий, коряво прикрученный костыль. Неудивительно, что его отправили на свалку истории.
                        Цитата Oleg2004 @
                        В общем, заморачиваться по этому поводу :"таймаут в минуту - суровое испытание нервов юзера)?" - я не вижу абсолютно никакого смысла. Пусть юзверь понимает, что есть вещи, с которыми мы обязаны сосуществовать.

                        Отлично! В таком случае желаю всегда сидеть под браузером, подвисающим на полторы минуты для каждого коннекта, ибо сервер недоступен, а есть вещи, "с которыми юзеры обязаны сосуществовать". А еще чтобы ping тоже по такому принципу работал. И мессенджеры.
                          Цитата Oleg2004 @
                          ^D^ima
                          Вы неправы. :)
                          Пинг лишь определяет что компутер включен в сеть и на нем функционирует стек TCP/IP
                          Отвечает модуль ICMP, который к никакому серверу не имеет отношения.

                          Формально вы правы, но это решит проблему "при подключении к хосту, который не работает"
                            Цитата Fr0sT @
                            "неблокирующий" сокет - в просторечии сокет в неблокирующем режиме.

                            Ну вот, уже точнее :)
                            Цитата Fr0sT @
                            А мне плевать на "исполнение коннекта" именно данного конкретного сокета.

                            Если так ставить проблему - то такое решение имеет право на существование.
                            Но оно - такое решение - брутально-кривое. Увы.
                            Цитата Fr0sT @
                            Не помешает почитать справку по этой функции

                            Я с этой функцией работал еще лет 20 тому назад. Так что уверяю вас, что в курсе.
                            Цитата Fr0sT @
                            Вообще вся эта система хуков на сокетах какой-то странный неуклюжий, коряво прикрученный костыль. Неудивительно, что его отправили на свалку истории.

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

                            Цитата Fr0sT @
                            В таком случае желаю всегда сидеть под браузером, подвисающим на полторы минуты для каждого коннекта, ибо сервер недоступен,

                            Не проблема. Любой адекватный пользователь знает что поведение сети непредсказуемо, и если одна закладка броузера тупит, делаем другую и работаем с другим сервером, пока не установится соединение или нас не пошлют.
                            Такова селяви однако. Никто не знает, когда установится соединение - "моментально", через 5 сек., через 15 сек или вообще не пройдет. Нетерпеливых просим не беспокоиться. :yes:
                              Цитата Oleg2004 @
                              Если так ставить проблему - то такое решение имеет право на существование.
                              Но оно - такое решение - брутально-кривое. Увы.

                              Чем?
                              Цитата Oleg2004 @
                              Я с этой функцией работал еще лет 20 тому назад.

                              20 лет тому назад и через 20h многое делали, но это же не значит, что так надо делать сейчас.
                              Можно поспорить: провести опрос, кто из здешних вообще знает про такую функцию. Я уж не говорю про применение в проектах.
                              Цитата Oleg2004 @
                              Насчет селекта я писал уже как то давно на нашем форуме. Так что повторяться не буду.

                              Неубедительно
                              Цитата Oleg2004 @
                              А цикл - жрет процессорное время и в результате эффект от автономного исполнения функции чисто в неблокирующем режиме нивелируется. Но для расточительных такое вполне приемлемо.

                              Это одна-то итерация раз в 50 мс жрет? Не смешите мои тапочки.
                              Цитата Oleg2004 @
                              Не проблема. Любой адекватный пользователь знает что поведение сети непредсказуемо, и если одна закладка броузера тупит, делаем другую и работаем с другим сервером, пока не установится соединение или нас не пошлют.
                              Такова селяви однако. Никто не знает, когда установится соединение - "моментально", через 5 сек., через 15 сек или вообще не пройдет. Нетерпеливых просим не беспокоиться.

                              Это вообще без комментариев, по-моему, именно по такому принципу создавалась сетевая часть IE6, который на диалапе мог свести с ума минут за десять.
                                Цитата Fr0sT @
                                20 лет тому назад и через 20h многое делали, но это же не значит, что так надо делать сейчас.
                                Можно поспорить: провести опрос, кто из здешних вообще знает про такую функцию. Я уж не говорю про применение в проектах.

                                Никто - и я тоже - не станет утверждать что такое надо делать сейчас. Есть нормальные асинхронные функции в АПИ сокетов, вот их и надо использовать.
                                Но идея прерывания исполнения коннекта есть нонсенс. Вот и все что я хочу сказать по этому поводу.
                                Весь остальной разговор на эту тему считаю просто троллингом.
                                  Неподдерживаемые замшелые механизмы ничем не лучше закрытия во время коннекта, тем более, что насчет гипотетического вреда последнего убедительных доводов не приведено.
                                    Если бы вы внимательно читали мои посты, то поняли, что я не предлагал использовать замшелые :D механизмы, а рассмотрел два варианта возможной идеологии решения этой проблемы.
                                    Это - раз. И самое главное, я вам показал, что изменить внутренний таймаут коннекта внешними способами нет никакой возможности. Разве что написать свой собственный вариант этой функции и интегрировать его в АПИ.
                                    По поводу вреда.
                                    Я нигде не писал о том, что ваш способ вреден. Он просто коряв - ИМХО.
                                    Потому как практически равносилен простому нажатию крестика на закладке, которая долго коннектится.
                                    Так что считаю дальнейшие препирания по этому поводу неуместными.
                                    Сообщение отредактировано: Oleg2004 -
                                      Цитата Oleg2004 @
                                      я не предлагал использовать замшелые механизмы

                                      Ну да, а функция упомянулась просто так, до кучи
                                      Цитата Oleg2004 @
                                      рассмотрел два варианта возможной идеологии решения этой проблемы.

                                      Это асинхронное выполнение в отдельном треде - вариант? Ну, формально и гланды можно удалять через анус, никто не запрещает, но...
                                      Цитата Oleg2004 @
                                      И самое главное, я вам показал, что изменить внутренний таймаут коннекта внешними способами нет никакой возможности. Разве что написать свой собственный вариант этой функции и интегрировать его в АПИ.

                                      Чудесно! Теперь остается выяснить, с какой целью доказывались очевидные вещи.
                                      Цитата Oleg2004 @
                                      По поводу вреда.
                                      Я нигде не писал о том, что ваш способ вреден. Он просто коряв - ИМХО.
                                      Потому как практически равносилен простому нажатию крестика на закладке, которая долго коннектится.

                                      "Брутально-кривой нонсенс" <> "Мне кажется, этот способ корявый"

                                      В общем, ТС спрашивал - я привел код, который делает то, что нужно. И он в самом деле это делает, невзирая на возражения пуристов. И если альтернативой насильственному закрытию сокета будет томительное и никак не контролируемое ожидание результата соединения - то я лично не буду проливать слезы по грубому вмешательству в тонкую душевную организацию сокета во время интимного процесса установки коннекта. Чего и всем остальным советую.

                                      Цитата Oleg2004 @
                                      Так что считаю дальнейшие препирания по этому поводу неуместными.

                                      Adios!
                                        мож сам телек как то надо прописать в маршрутезаторе?
                                        1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                        0 пользователей:


                                        Рейтинг@Mail.ru
                                        [ Script execution time: 0.1058 ]   [ 15 queries used ]   [ Generated: 23.08.26, 23:35 GMT ]