На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
    > recv с неблокирующим сокетом , не отключается из другого потока
      В линукс к моему удивлению вызванная в процессе функция close не закрывает сокет, который висит на прослушивании функцией recv. Уверен что в винде синхронный сокет закроется. Из ситуации можно выйти поставив на recv тайм-аут, но опять же закрытие сокета произойдет после
      тайм-аута. Как мгновенно отключить сокет?
      Сообщение отредактировано: ter_nk_ -
        Таймаут для recv здесь делать нельзя, будет отваливаться при получении данных.
        Для сокетов лучше в цикле вызывать select или poll с небольшим таймаутом ~10mc, потом recv, если пришли данные.
        Тогда не будет проблем с задержкой при остановке программы.
          У меня так и есть когда я тайм-аут добавил, он вываливается по тайм-ауту или по приходу данных, вариант не устраивает. Т.е. просто внешне я не могу отрубить сокет который в recv висит. Делать с select можно, просто тогда переделывать. Хотел без этого обойтись а просто разрывать соединение.
            Так у тебя сокет неблокирующий? А как он вообще в recv может зависнуть?
              Цитата Олег М @
              Так у тебя сокет неблокирующий? А как он вообще в recv может зависнуть?


              У меня блокирующий сокет, но я не мог его закрывать, добавил тайм-аут.
                Цитата ter_nk_ @
                У меня блокирующий сокет, но я не мог его закрывать, добавил тайм-аут.

                Да, я так сначала и подумал. Потом обратил внимание на тему.
                Он не закрывается скорее всего, потому что close не закрывает непосредственно дескриптор, а уменьшает какой-нибудь счётчик или типа того, и, если тот равен нулю, то закрывает. Т.е. ресурс не удаляется, пока кто-нибудь, в частности recv, держит ссылку на него.
                Проверь, что возвращает close(). А ещё есть функция shutdown(), попробуй, может она сможет отрубить recv.

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

                Обычно перед вызовом recv, я получаю кол-во данных в буфере сокета, FIONREAD, затем вызываю recv.
                  Цитата Олег М @
                  Он не закрывается скорее всего, потому что close не закрывает непосредственно дескриптор, а уменьшает какой-нибудь счётчик или типа того, и, если тот равен нулю, то закрывает. Т.е. ресурс не удаляется, пока кто-нибудь, в частности recv, держит ссылку на него.
                  Проверь, что возвращает close(). А ещё есть функция shutdown(), попробуй, может она сможет отрубить recv.


                  Да, вот точно, вот что надо будет проверить.

                  Цитата Олег М @
                  Таймаут на recv ставится когда тебе нужно обязательно получить строго определённое количество данных, причём лично я обычно ставлю 30 сек. Но использую такое крайне редко.
                  Если поставить маленький таймаут, то recv может отвалится во время получения данных, просто не успеет всё вычитать, либо сервер не успеет передать. Тогда ты не отличишь сбой соединения от нормальной работы.


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

                  Цитата Олег М @
                  Обычно перед вызовом recv, я получаю кол-во данных в буфере сокета, FIONREAD, затем вызываю recv.


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

                  Спасибо!
                    Вот кое какие сведения на этот счет:
                    Цитата
                    Результаты закрытия сокета с помощью close() существенно отличается от результата вызова shutdown(). По сути вызов shutdown() не закрывает сокет по-настоящему, даже если он осуществлен с параметром 2. Ни сокет, ни ассоциированные с ним ресурсы (за исключением буфера приема при how=0 или 2) система не освобождает.
                    Особо отметим, что вызов shutdown() воздействует на все процессы, для которых этот сокет является открытым (например, в дочернем процессе после вызова fork()). В результате вызов shutdown() с параметром how=1 запретит запись в этот сокет всем использующим его процессам. При вызове же close() или его Windows-аналога closesocket() все другие процессы могут продолжать пользоваться сокетом.
                    Если надо окончательно закрыть (и уничтожить) конкретный сокет в данном процессе, после shutdown() с параметрами 0 или 1 надо вызывать close().
                    Вызывая shutdown() с how=1, отправитель будет точно знать, что другая сторона получит признак конца переданного файла EOF, даже если этот сокет открыт и другими процессами. При вызове close() или closesocket() это не гарантируется, поскольку TCP не пошлет FIN-сегмент, пока счетчик ссылок на данный сокет не станет равным нулю – т.е. когда все процессы закроют этот сокет.
                    С помощью shutdown() реализуется так называемое аккуратное размыкание (orderly release) соединения, в результате чего обе стороны получат все предназначенные им данные до того, как соединение будет разорвано.
                    Резюме: В Windows принято, что после вызова closesocket() соединение закрывается. Так же соединения закрываются при закрытии программы. Система знает, какому процессу соответствуют сокеты, и закрывает их при смерти приложения.
                    В Linix и FreeBSD это не так. Необходимо явно сказать shutdown() (посылка FIN) и close() (разъединение дескриптора и сокета). Если этого не сделать, то после закрытия приложения сокеты еще будут висеть в системе некоторое время, в течение которого bind() на "занятые" порты будет возвращать ошибку.
                      Спасибо, второй Олег!
                        да, все работает c shutdown(socket, 1) !
                          ter_nk_ :D
                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0330 ]   [ 17 queries used ]   [ Generated: 28.03.24, 18:19 GMT ]