Как узнать что сокет закрыт c

Обновлено: 03.07.2024

ОТВЕТЫ

Ответ 1

Как Пол Тернер ответил Socket.Connected не может быть использован в этой ситуации. Вы должны каждый раз проверять соединение, чтобы узнать, включено ли соединение. Это код, который я использовал:

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

  • s.Poll возвращает true, если
    • соединение закрыто, reset, завершено или ожидает (что означает отсутствие активного соединения)
    • активно и доступны данные для чтения
    • нет данных для чтения, поэтому соединение неактивно

    Ответ 2

    Как zendar написал, хорошо использовать Socket.Poll и Socket.Available , но вам нужно учитывать, что сокет, возможно, не был инициализирован в первую очередь. Это последняя (я считаю) часть информации, и она предоставляется свойством Socket.Connected . Пересмотренная версия метода будет выглядеть примерно так:

    Ответ 3

    Свойство Socket.Connected сообщит вам, считает ли сокет его подключением. Он фактически отражает состояние последней операции отправки/получения, выполняемой в сокете.

    Вы можете проверить свойство после возникновения исключения, но оно не является надежным до этого.

    Ответ 4

    Принятый ответ не работает, если вы отключите сетевой кабель. Или сервер сбой. Или ваш маршрутизатор падает. Или если вы забудете оплатить свой интернет-счет. Задайте параметры сохранения TCP для лучшей надежности.

    Таким образом, приведенные выше значения приведут к обнаружению 2 + 10 * 1 = 12 секунд. После этого любые операции чтения /wrtie/poll не будут выполняться в сокете.

    Ответ 5

    Я сделал метод расширения, основанный на этой статье MSDN. Вот как вы можете определить, все еще подключен сокет.

    Ответ 6

    Я столкнулся с той же проблемой, что и при использовании сокетов, и это был единственный способ сделать это. Свойство socket.connected никогда не было правильным.

    В конце концов, я переключился на использование WCF, потому что он был намного надежнее, чем сокеты.

    Ответ 7

    Следуя советам NibblyPig и zendar, я придумал код ниже, который работает на каждом испытании, которое я сделал. В итоге мне потребовались как пинг, так и опрос. Пинг сообщит мне, отсоединен ли кабель или физический уровень в противном случае нарушен (отключен маршрутизатор и т.д.). Но иногда после повторного подключения я получаю RST, ping в порядке, но состояние tcp не является.

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

    As Пол Тернер ответил Socket.Connected не может использоваться в этой ситуации. Вы должны опрашивать соединение каждый раз, чтобы увидеть, если соединение все еще активно. Это код, который я использовал:

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

    • s.Poll возвращает true, если
      • соединение закрыто, сброшено, прекращено или ожидает (что означает отсутствие активного соединения)
      • соединение активно и данные доступны для чтения
      • нет данных, доступных для чтения, поэтому соединение не активно

      As zendar написал, приятно использовать Socket.Poll и Socket.Available , но вам нужно принять во внимание, что сокет, возможно, не был инициализирован в первую очередь. Это последняя (я считаю) часть информации, и она предоставляется Socket.Connected собственность. Пересмотренная версия метода будет выглядеть примерно так:

      на Socket.Connected свойство скажет вам, является ли сокет думает это связано. Он фактически отражает состояние последней операции отправки/получения, выполненной на сокете.

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

      принятый ответ, похоже, не работает, если вы отключите сетевой кабель. Или сервер аварийно завершает работу. Или ваш маршрутизатор аварийно завершает работу. Или если вы забыли оплатить счет за интернет. Установите параметры TCP keep-alive для повышения надежности.

      таким образом, приведенные выше значения приведут к 2+10*1 = 12 второе обнаружение. После этого любые операции чтения / wrtie / опроса должны завершиться неудачей в сокете.

      Я сделал метод расширения на основе этой статья MSDN. Таким образом можно определить, подключен ли сокет.

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

      Я столкнулся с той же проблемой, что и вы при использовании сокетов, и это был единственный способ сделать это. Розетка.свойство connected никогда не было правильным.

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

      следуя совету от NibblyPig и zendar, Я придумал код ниже, который работает на каждом тесте, который я сделал. В итоге мне понадобился и пинг, и опрос. Пинг даст мне знать, если кабель был отключен, или физический уровень иначе нарушен (маршрутизатор выключен и т. д.). Но иногда после повторного подключения я получаю первый, пинг в порядке, но состояние tcp-нет.

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

      Закрывает подключение Socket и освобождает все связанные ресурсы.

      Перегрузки

      Закрывает подключение Socket и освобождает все связанные ресурсы.

      Закрывает подключение Socket и освобождает все связанные ресурсы с заданным временем ожидания, чтобы разрешить отправку данных в очереди.

      Close()

      Закрывает подключение Socket и освобождает все связанные ресурсы.

      Примеры

      В следующем примере кода закрывается Socket .

      Комментарии

      CloseМетод закрывает подключение к удаленному узлу и освобождает все управляемые и неуправляемые ресурсы, связанные с Socket . После закрытия Connected свойству присваивается значение false .

      Для протоколов, ориентированных на соединение, рекомендуется вызывать Shutdown метод перед вызовом Close метода. Это гарантирует, что все данные отправляются и получаются на подключенном сокете до его закрытия.

      Если необходимо вызвать Close без первого вызова Shutdown , можно убедиться, что данные, поставленные в очередь для исходящей передачи, будут отправлены, задав DontLinger Socket для параметра значение false и указав интервал времени ожидания, отличный от нуля. Close будет блокироваться до тех пор, пока эти данные не будут отправлены или пока не истечет указанное время ожидания. Если задано DontLinger значение false и задан нулевой интервал времени ожидания, Close освобождает соединение и автоматически удаляет исходящие данные из очереди.

      Чтобы присвоить DontLinger параметру сокета значение false , создайте LingerOption , задайте для свойства Enabled значение true , а для LingerTime Свойства — требуемый период времени ожидания. Используйте его LingerOption вместе с DontLinger параметром Socket для вызова SetSocketOption метода.

      См. также раздел

      Применяется к

      Close(Int32)

      Закрывает подключение Socket и освобождает все связанные ресурсы с заданным временем ожидания, чтобы разрешить отправку данных в очереди.

      Параметры

      Примеры

      В следующем примере кода показано, как закрыть Socket .

      Комментарии

      CloseМетод закрывает подключение к удаленному узлу и освобождает все управляемые и неуправляемые ресурсы, связанные с Socket . После закрытия Connected свойству присваивается значение false .

      Для протоколов, ориентированных на соединение, рекомендуется вызывать метод Shutdown перед вызовом метода Close . Это гарантирует, что все данные отправляются и получаются на подключенном сокете до его закрытия.

      Если необходимо вызвать Close без первого вызова Shutdown , можно убедиться, что данные, поставленные в очередь для исходящей передачи, будут отправлены, задав DontLinger для параметра значение false и указав интервал времени ожидания, отличный от нуля. Close будет блокироваться до тех пор, пока эти данные не будут отправлены или пока не истечет указанное время ожидания. Если задано DontLinger значение false и задан нулевой интервал времени ожидания, Close освобождает соединение и автоматически удаляет исходящие данные из очереди.

      Чтобы присвоить DontLinger параметру сокета значение false , создайте LingerOption , задайте для свойства Enabled значение true и задайте LingerTime для свойства требуемый период ожидания. Используйте его LingerOption вместе с DontLinger параметром Socket для вызова SetSocketOption метода.

      Репутация: нет
      Всего: 3

      Здравствуйте.
      Знаю, что вопрос относительно тривиальный, но обращаюсь за помощью и что бы разобраться в ситуации.

      Пишу под Linux. Работаю с сокетами. Использую "чистый" C.

      Благополучно соединяюсь с ним, работаю, по завершению работы или при возникновении ошибок делаю его close(sock_descr).
      Далее, в зависимости от ситуации, мне нужно повторно использовать sock_descr.
      Либо повторно им воспользоваться, если я не делал ранее его close, либо заново сделать connect и пользоваться им.
      Вопрос заключается в следующем:
      как в определенном месте однозначно надежно (и по возможности просто) выяснить, что этот дескриптор сокета был ранее closed?

      Решение этого вопроса гуглил, но в ходу не совсем очевидные мне методы выяснения статуса сокета. Рекомендуют использовать read/write, но у меня вызывает сомнение использование этого метода.
      Адекватный ли вариант "мануально" контролировать статус сокета посредством использования рукописной структуры?
      Пример:

      Код

      struct MySocket int socket_descriptor;
      int status; //Статус сокета. Каждый раз при вызове close устанавливать его руками.
      >

      Репутация: 1
      Всего: 45

      Довольно странный подход. Если сокет был закрыт, то его дескриптор становится свободным, а память под внутренние структуры высвобождена. Как его можно использовать? Никак. К тому же любой последующий open/fopen/socket может занять этот дескриптор, и прощай надежды.


      Опять-таки, после закрытия сокета его использовать никоим образом нельзя. Поэтому очень часто пишут так: Присвоение переменной сокета значения -1 как раз и будет указывать на то, что сокет был закрыт. Дополнительного значения status здесь не требуется. В дальнейшем в коде можно просто делать проверку на положительность значения переменной сокета: Напильник, велосипед, грабли и костыли - основные инструменты программиста.

      Репутация: нет
      Всего: 3

      Перечитал свой первый пост, достаточно запутанно описал ситуацию.
      По сути, в случае ошибки, мне нужно делать полное переподключение и я использую один и тот же дескриптор сокета.
      Как выходить из этой ситуации?
      Вручную присваивать дескриптору после close значение -1? Как в таком случае открывать этот дескриптор повторно?

      Репутация: нет
      Всего: 459

      гениальность идеи состоит в том, что ее невозможно придумать

      Репутация: 1
      Всего: 45

      В случае какой ошибки? Ошибки бывают слишком разные.


      Зачем? В чем причина необходимости для использования того же дескриптора сокета? Почему бы просто не закрыть сокет, а потом его по-новой открыть в случае переподключения? У Вас им удерживается свой IP:port?
      Напильник, велосипед, грабли и костыли - основные инструменты программиста.

      Репутация: нет
      Всего: 3

      Alexeis, ООП использовать не могу - "чистый" Си.
      feodorv, по поводу ошибок. Имеются ввиду ошибки при подключении или при обмене данными (хост недоступен, порт занят, сервер не возвращает данные). В каждом из этих случаев мне необходимо осуществить несколько попыток повторного подключения. Я принял во внимание ваши советы, пересмотрел код. Вопросы стали еще проще и еще банальнее:
      1. Фактически close не изменяет значение дескриптора сокета, а лишь закрывает его. Верно? Т.е. после close я могу присвоить переменной в которой ранее хранился действующий дескриптор сокета отрицательное значение для индикации того, что сокет закрыт?
      2. Дескриптор действующего сокета не может быть отрицательным. Может ли дескриптор сокета быть равным 0?

      Репутация: 1
      Всего: 45

      По сути верно, по форме я бы иначе сказал. Дело в том, что переменная сокета хранит дескриптор сокета, и при close данный дескриптор высвобождается и более ничему не соответствует (ни файлу, ни сокету), хотя переменная сокета продолжает хранить значение этого уже освобождённого дескриптора. Чтобы она этого не делала, и для индикации закрытости сокета, стОит присвоить переменной сокета отрицательное значение (обычно используют -1).

      Не может. Более того, отрицательное значение, возвращаемое вызовом socket(), сигнализирует об ошибке.


      Вообще, значения дескрипторов 0, 1 и 2 отведены под stdin, stdout и stderr. Если их последовательно закрыть, а затем сделать вызов socket(), то вполне возможно получить нулевое значение дескриптора сокета. По крайней мере, так было в Юниксах лет 10 назад, к сожалению, меня с тех пор от них оторвали, я не в курсе последних тенденций в этом направлении. Но учитывая значительный консерватизм в разработке Юниксов, не думаю, что здесь что-то изменилось. Можно, кстати, поставить эксперимент. Но в любом случае по стандарту нужно быть готовым к тому, что значение дескриптора сокета может быть нулём)))
      Напильник, велосипед, грабли и костыли - основные инструменты программиста.

      Репутация: нет
      Всего: 3

      feodorv, большое спасибо! Вы все объяснили до очевидного понятно.
      Ответы на все сформулированные вопросы я получил. Тему закрою если не возникнет дополнительных вопросов при исправлении взаимодействия с сокетами в коде.

      Репутация: нет
      Всего: 3

      Помечаю вопрос как решенный.
      Воспользовался советами feodorv.

      Репутация: 4
      Всего: 4

      • Ваш сервер установил ТСР соединение с клиентом
      • Идёт приём данных от клиента
      • Что-то случилось на сервере и он закрывает все сокеты и пытается перестартоваться
      • Но приём данных не завешён и может быть завершён - неизвестно когда. ОС не освобождает сетевой адрес этого соединения
      • При повторном открытии сокета и его биндинге возникает конфликт

      Репутация: нет
      Всего: 459


      ОС закрывает соединение при возникновении любой неисправимой ошибки. Но это не имеет отношения к теме обсуждения. Автор спрашивал как проверить закрыт или открыт сокет, а не соединение. Сокет может быть открытым как при открытом так и при закрытом соединениях. Есть еще вариант проверки при помощи функции recv . После ожидания таймаута открытый сокет с открытым соединением вернет EAGAIN или EWOULDBLOCK. Закрытый сокет или в состоянии ошибки вернет код ошибки моментально. Но этот способ страдает таймаутом, так что не эффективен.

      гениальность идеи состоит в том, что ее невозможно придумать

      Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

      [ Время генерации скрипта: 0.1790 ] [ Использовано запросов: 21 ] [ GZIP включён ]

      Читайте также: