Что вызывает ошибку ENOTCONN? - PullRequest
17 голосов
/ 23 мая 2009

В настоящее время я поддерживаю некоторое программное обеспечение веб-сервера, и мне нужно выполнить много операций ввода-вывода. Вызовы read(), write(), close() и shutdown() при использовании в сокете могут иногда вызывать ошибку ENOTCONN. Что именно означает эта ошибка? Какие условия это вызвало бы? Я никогда не могу воспроизвести это локально, но есть пользователи, которые могут.

Прямо сейчас я просто игнорирую ENOTCONN при поднятии на close() и shutdown(), потому что это кажется безвредным, но я не совсем уверен.

EDIT:

  • Я абсолютно уверен, что вызов connect() завершился успешно. Я проверяю его возвращаемое значение.
  • ENOTCONN чаще всего повышается на close() и shutdown(). Я очень редко видел повышение read() и write() ENOTCONN.

Ответы [ 5 ]

18 голосов
/ 24 мая 2009

Если вы уверены, что ничто на вашей стороне TCP-соединения не закрывает соединение, то мне кажется, что удаленная сторона закрывает соединение.

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

Это отличается от:

  • ECONNRESET: другой конец соединения отправил пакет сброса TCP. Это может произойти, если другой конец отказывает в соединении или не признает, что оно уже подключено, среди прочего.
  • ETIMEDOUT: это обычно относится только к connect. Это может произойти, если попытка подключения не удалась в течение системно-зависимого промежутка времени.

EPIPE иногда может возвращаться некоторыми системными вызовами, связанными с сокетом, в условиях, которые более или менее совпадают с ENOTCONN. Например, в некоторых системах EPIPE и ENOTCONN являются синонимами, когда возвращаются send.

Хотя для shutdown не является необычным возвращение ENOTCONN, поскольку предполагается, что эта функция разрывает TCP-соединение, я был бы удивлен, увидев close return ENOTCONN. Это действительно никогда не должно делать это.

Наконец, как упоминалось в dwc, EBADF не должно применяться в вашем сценарии, если вы не пытаетесь выполнить какую-либо операцию с файловым дескриптором, который уже был close d. Отключение сокета (т. Е. Разрыв соединения TCP) - это не то же самое, что закрытие дескриптора файла, связанного с этим сокетом.

1 голос
/ 12 июня 2013

Это потому, что в момент закрытия () сокета у вас есть данные в буфере сокета, ожидающие доставки удаленной стороне, которая закрыла () или закрыла () свой приемный сокет. Я не до конца понимаю, как работают сокеты, я скорее нуб, и мне не удалось даже найти файлы, в которых реализована эта функция «выключения», но я вижу, что практически нет руководства пользователя для всего, что я начал с сокетами пробуя все возможности, пока я не получил ошибку в «контролируемой» среде. Это может быть что-то еще, но после долгих попыток я согласился с объяснениями:

  • Если вы отправили данные после того, как удаленная сторона закрыла соединение, при выключении () вы получите ошибку.
  • Если вы отправили данные до того, как удаленная сторона закрыла соединение, но оно не было получено () на другом конце, вы можете отключить () один раз, при следующей попытке выключить () вы получите ошибку.
  • Если вы не отправляли какие-либо данные, вы можете завершить работу в любое время, пока удаленная сторона не отключится (); если на удаленной стороне есть shutdown (), если вы попытаетесь shutdown () и сокет уже выключен (), вы получите ошибку.
1 голос
/ 15 апреля 2013

Я считаю, что ENOTCONN возвращается, потому что shutdown () не должен возвращать ECONNRESET или другие более точные ошибки.

Неправильно полагать, что другая сторона «просто» закрыла соединение. На уровне TCP другая сторона может только наполовину закрыть соединение (или прервать его). Соединение обычно полностью закрыто, если обе стороны делают shutdown () (или close ()). Если обе стороны это сделают, shutdown () фактически будет успешным для них обоих!

Проблема в том, что shutdown () не преуспел в обычном (наполовину) закрытии соединения, ни в качестве первого, чтобы закрыть его, ни в качестве второго. - Из ошибок, перечисленных в документации POSIX для shutdown (), ENOTCONN является наименее неуместным, поскольку другие указывают на проблемы с аргументами, передаваемыми shutdown () (или проблемы с локальными ресурсами для обработки запроса).

Так что случилось? В наши дни устройство NAT где-то между двумя вовлеченными сторонами, возможно, отбросило ассоциацию и отправило пакеты RESET в качестве реакции. Сброс соединений настолько распространен для IPv4, что вы получите их в любом месте кода, даже в ENOTCONN в shutdown ().

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

0 голосов
/ 23 мая 2009

Если вы уверены, что вы правильно подключились, то ENOTCONN, скорее всего, будет вызвано закрытием fd на вашем конце (возможно, в другом потоке?), Пока вы в середине запроса или из-за разрыва соединения, пока вы находитесь в середине запроса.

В любом случае это означает, что розетка не подключена. Идите и почистите это гнездо. Он мертв. Нет проблем с вызовом close() или shutdown().

0 голосов
/ 23 мая 2009

Конечная точка транспорта не подключена

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

От: http://www.wlug.org.nz/ENOTCONN

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...