Я понимаю, что для сокетов TCP ECONNRESET имеет какое-то отношение к пакетам RST. Но я также видел ошибки ECONNRESET для сокетов AF_LOCAL, при вызовах read() и write(). Что это значит? Как ECONNRESET отличается от read(), возвращающего 0 или write(), бросающего EPIPE?
Что означает ECONNRESET в контексте сокета AF_LOCAL?
Ответ 1
Похоже, что ECONNRESET означает, что другая сторона закрыла соединение, не читая выданные данные, которые были отправлены ему, и может быть запущена как для чтения(), так и для записи(). Но точное поведение зависит от операционной системы.
EPIPE
Кажется, срабатывает, когда одна запись() s в уже созревший сокет, и нет выдающихся исходящих данных. Применяется как для сокетов PF_LOCAL, так и для TCP. Пример (Ruby):
a, b = UNIXSocket.pair
b.close
a.write("foo") # => EPIPE, on all OSes
read() возвращает 0
Запускается, когда другая сторона закрыла соединение, и нет выдающихся исходящих данных. Применимо к сокетам PF_LOCAL и TCP.
a, b = UNIXSocket.pair
b.close
a.read # => 0 bytes, on all OSes
ECONNRESET
В Linux он ведет себя следующим образом:
Запускается, когда имеются выдающиеся исходящие данные, которые еще не были записаны на другую сторону. read() запускает его как для сокетов PF_LOCAL, так и для TCP, но write() запускает его только для сокетов TCP; Соединители PF_LOCAL запускают EPIPE.
См. примеры для конкретного поведения ОС. Пожалуйста, внесите свой вклад, если вы знаете, как ведут себя другие ОС.
Пример 1: чтение() в сокете PF_LOCAL
a, b = UNIXSocket.pair
a.write("hello")
b.close
a.read
# Linux: ECONNRESET
# OS X : returns 0 bytes
Пример 2: read() в сокете TCP
# Side A # Side B
s = TCPServer.new('127.0.0.1', 3001)
c = s.accept
c = TCPSocket.new('127.0.0.1', 3001)
c.write("hello")
c.close
c.read
# Linux: ECONNRESET
# OS X : returns 0 bytes
Пример 3: write() в сокете PF_LOCAL
a, b = UNIXSocket.pair
a.write("hello")
b.close
a.write("world")
# Linux: EPIPE and not ECONNRESET
# OS X : EPIPE and not ECONNRESET
Пример 4: write() в сокете TCP
# Side A # Side B
s = TCPServer.new('127.0.0.1', 3001)
c = s.accept
c = TCPSocket.new('127.0.0.1', 3001)
c.write("hello")
c.close
c.write("world")
# Linux: ECONNRESET
# OS X : no error