Подтвердить что ты не робот

104, 'Соединение reset по ошибке сокета peer', или Когда закрытие сокета приводит к RST, а не FIN?

Мы разрабатываем веб-сервис Python и веб-сайт клиента параллельно. Когда мы делаем HTTP-запрос от клиента к службе, один вызов последовательно вызывает socket.error в socket.py, в read:

(104, 'Connection reset by peer')

Когда я слушаю с помощью wirehark, "хорошие" и "плохие" ответы выглядят очень похожими:

  • Из-за размера заголовка OAuth запрос разбивается на два пакета. Служба отвечает как с помощью ACK
  • Служба отправляет ответ, один пакет на заголовок (HTTP/1.0 200 OK, затем заголовок Date и т.д.). Клиент отвечает каждому из ACK.
  • (Хороший запрос) сервер отправляет FIN, ACK. Клиент отвечает FIN, ACK. Сервер отвечает ACK.
  • (неверный запрос) сервер отправляет RST, ACK, клиент не отправляет ответ TCP, socket.error возникает на стороне клиента.

Как веб-служба, так и клиент работают на блоке x86-64 Gentoo Linux, работающем под управлением glibc-2.6.1. Мы используем Python 2.5.2 внутри того же virtual_env.

Клиент - это приложение Django 1.0.2, которое вызывает запросы httplib2 0.4.0. Мы подписываем запросы с помощью алгоритма подписи OAuth, а токен OAuth всегда задает пустую строку.

В службе работает Werkzeug 0.3.1, которая использует Python wsgiref.simple_server. Я запускал приложение WSGI через wsgiref.validator без проблем.

Похоже, что это должно быть легко отлаживать, но когда я просматриваю хороший запрос со стороны службы, он выглядит так же, как неудачный запрос, в функции socket._socketobject.close(), превращая методы делегата в манекен методы. Когда метод send или sendto (не может запомнить, который) отключен, FIN или RST отправляются, и клиент начинает обработку.

"Соединение reset by peer", похоже, накладывает вину на службу, но я не доверяю httplib2. Может ли клиент быть виноват?

** Дальнейшая отладка - выглядит как сервер на Linux **

У меня есть MacBook, поэтому я попытался запустить службу на одном и на веб-сайте клиента на другом. Клиент Linux вызывает сервер OS X без ошибки (FIN ACK). Клиент OS X вызывает службу Linux с ошибкой (RST ACK и (54, "Соединение reset одноранговым узлом" )). Итак, похоже, что это служба, работающая в Linux. Это x86_64? Плохое glibc? wsgiref? Еще глядя...

** Дальнейшее тестирование - wsgiref выглядит flaky **

Мы пошли на производство с Apache и mod_wsgi, а сбрасываем соединение. См. Мой ответ ниже, но мой совет - зарегистрировать соединение reset и повторить попытку. Это позволит вашему серверу нормально работать в режиме разработки и прочно работать.

4b9b3361

Ответ 1

У меня была эта проблема. См. Проблема" Соединение Reset по протоколу Python > .

У вас есть (скорее всего) проблемы с малыми сроками, основанные на блокировке Python Global Interpreter Lock.

Вы можете (иногда) исправить это с помощью time.sleep(0.01), размещенного стратегически.

"Где?" ты спрашиваешь. Ударь меня. Идея состоит в том, чтобы обеспечить лучший поток concurrency внутри и вокруг клиентских запросов. Попробуйте поместить его непосредственно перед тем, как сделать запрос так, чтобы GIL был Reset, и интерпретатор Python мог очистить любые отложенные потоки.

Ответ 2

Не используйте wsgiref для производства. Используйте Apache и mod_wsgi, или что-то еще.

Мы продолжаем видеть, что эти соединения сбрасываются, иногда часто, с помощью wsgiref (бэкэнд, используемый тестовым сервером werkzeug и, возможно, другими, такими как тестовый сервер Django). Наше решение заключалось в регистрации ошибки, повторении вызова в цикле и сдаче после десяти сбоев. httplib2 пытается дважды, но нам нужно еще несколько. Кажется, что они приходят в пучки - добавление 1-го сна может устранить проблему.

Мы никогда не видели соединение reset при работе через Apache и mod_wsgi. Я не знаю, что они делают по-другому (возможно, они просто маскируют их), но они не появляются.

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

Ответ 4

Обычно вы получаете RST, если вы выполняете закрытие, которое не задерживается (т.е. данные могут быть отброшены стеком, если он не был отправлен, и ACK'd) и нормальный FIN, если вы позвольте близко задерживаться (т.е. закрытие ожидает, что данные в пути будут ACK'd).

Возможно, все, что вам нужно сделать, это установить, чтобы ваш сокет задерживался, чтобы вы удалили условие гонки между незатухающим закрытием, сделанным на сокете и прибывшими ACK?