Модераторы: xvr
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как проверить закрыт ли сокет, Как проверить что сокет был close? 
V
    Опции темы
Zerstroer
Дата 12.8.2015, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

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



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

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

Создаю сокет:

Код

   int sock_descr = socket(AF_INET, SOCK_STREAM, 0);


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

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

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


Заранее спасибо.



--------------------
In silico
PM MAIL ICQ   Вверх
feodorv
Дата 12.8.2015, 15:58 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

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



Цитата(Zerstroer @  12.8.2015,  14:22 Найти цитируемый пост)
Либо повторно им воспользоваться, если я не делал ранее его close, либо заново сделать connect и пользоваться им.

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


Цитата(Zerstroer @  12.8.2015,  14:22 Найти цитируемый пост)
Адекватный ли вариант "мануально" контролировать статус сокета посредством использования рукописной структуры? 

Опять-таки, после закрытия сокета его использовать никоим образом нельзя. Поэтому очень часто пишут так:
Код
if( sock >= 0 ) close( sock );
sock = -1;
Присвоение переменной сокета значения -1 как раз и будет указывать на то, что сокет был закрыт. Дополнительного значения status здесь не требуется. В дальнейшем в коде можно просто делать проверку на положительность значения переменной сокета:
Код
if( sock >= 0 ) send( sock, ...);




--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Zerstroer
Дата 12.8.2015, 19:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

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



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



--------------------
In silico
PM MAIL ICQ   Вверх
Alexeis
Дата 12.8.2015, 19:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

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



Цитата(feodorv @  12.8.2015,  16:58 Найти цитируемый пост)
Присвоение переменной сокета значения -1 как раз и будет указывать на то, что сокет был закрыт.

  ООП наш лучший друг в слежении за ресурсами.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
feodorv
Дата 12.8.2015, 20:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

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



Цитата(Zerstroer @  12.8.2015,  19:47 Найти цитируемый пост)
По сути, в случае ошибки

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

Цитата(Zerstroer @  12.8.2015,  19:47 Найти цитируемый пост)
мне нужно делать полное переподключение и я использую один и тот же дескриптор сокета.

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


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Zerstroer
Дата 12.8.2015, 20:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

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



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


--------------------
In silico
PM MAIL ICQ   Вверх
feodorv
Дата 12.8.2015, 21:03 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

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



Цитата(Zerstroer @  12.8.2015,  20:29 Найти цитируемый пост)
1. Фактически close не изменяет значение дескриптора сокета, а лишь закрывает его. Верно? Т.е. после close я могу присвоить переменной в которой ранее хранился действующий дескриптор сокета отрицательное значение для индикации того, что сокет закрыт?

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


Цитата(Zerstroer @  12.8.2015,  20:29 Найти цитируемый пост)
Дескриптор действующего сокета не может быть отрицательным.

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


Цитата(Zerstroer @  12.8.2015,  20:29 Найти цитируемый пост)
Может ли дескриптор сокета быть равным 0? 

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


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Zerstroer
Дата 12.8.2015, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

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



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


--------------------
In silico
PM MAIL ICQ   Вверх
Zerstroer
Дата 13.8.2015, 12:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 8.8.2007
Где: Алма-Ата

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



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


--------------------
In silico
PM MAIL ICQ   Вверх
svlary
Дата 17.8.2015, 14:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 207
Регистрация: 8.9.2009

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



Цитата(Zerstroer @  12.8.2015,  21:14 Найти цитируемый пост)
до очевидного понятно.


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

 Было у меня это очень давно и потому "помню туманно" smile
Но там как-то надо использовать опцию сокета SO_REUSEBLE_ADDR.  Как-то так она пишется...

PM MAIL   Вверх
Alexeis
Дата 17.8.2015, 15:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

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



Цитата(svlary @  17.8.2015,  15:33 Найти цитируемый пост)
Но приём данных не завешён и может быть завершён - неизвестно когда. ОС не освобождает сетевой адрес этого соединения

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


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

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

 
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




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


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.