Что вызывает ошибку ENOTCONN?

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

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

EDIT:

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

Ответ 1

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

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

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

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

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

Ответ 4

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

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

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

Ответ 5

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

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