【问题标题】:104, 'Connection reset by peer' socket error, or When does closing a socket result in a RST rather than FIN?104, 'Connection reset by peer' 套接字错误,或关闭套接字何时导致 RST 而不是 FIN?
【发布时间】:2010-09-27 21:04:32
【问题描述】:

我们正在同时开发 Python Web 服务和客户端网站。当我们从客户端向服务发出 HTTP 请求时,一个调用会在 socket.py 中持续引发一个 socket.error,如下所示:

(104, '连接被对端重置')

当我用wireshark收听时,“好”和“坏”的反应看起来非常相似:

  • 由于 OAuth 标头的大小,请求被分成两个数据包。服务使用 ACK 响应两者
  • 服务发送响应,每个标头一个数据包(HTTP/1.0 200 OK,然后是 Date 标头等)。客户端用 ACK 响应每个。
  • (良好请求)服务器发送一个 FIN、ACK。客户端以 FIN、ACK 响应。服务器响应 ACK。
  • (错误请求)服务器发送 RST、ACK,客户端不发送 TCP 响应,客户端引发 socket.error。

Web 服务和客户端都在运行 glibc-2.6.1 的 Gentoo Linux x86-64 机器上运行。我们在同一个 virtual_env 中使用 Python 2.5.2。

客户端是一个 Django 1.0.2 应用程序,它调用 httplib2 0.4.0 来发出请求。我们使用 OAuth 签名算法对请求进行签名,OAuth 令牌始终设置为空字符串。

该服务正在运行 Werkzeug 0.3.1,它使用 Python 的 wsgiref.simple_server。我通过 wsgiref.validator 运行 WSGI 应用程序没有任何问题。

看起来这应该很容易调试,但是当我在服务端跟踪一个好的请求时,它看起来就像是错误的请求,在 socket._socketobject.close() 函数中,将委​​托方法变成了虚拟的方法。当send或sendto(不记得是哪个)方法关闭时,发送FIN或RST,客户端开始处理。

“对等连接重置”似乎将责任归咎于服务,但我也不信任 httplib2。客户有错吗?

** 进一步调试 - 看起来像 Linux 上的服务器 **

我有一台 MacBook,所以我尝试在一台上运行服务,在另一台上运行客户端网站。 Linux 客户端调用 OS X 服务器时没有错误 (FIN ACK)。 OS X 客户端调用带有错误的 Linux 服务(RST ACK 和 (54, 'Connection reset by peer'))。因此,它看起来像是在 Linux 上运行的服务。是 x86_64 吗?一个糟糕的 glibc? wsgiref?还在找……

** 进一步测试 - wsgiref 看起来很不稳定 **

我们已经使用 Apache 和 mod_wsgi 投入生产,连接重置已经消失。请参阅下面的答案,但我的建议是记录连接重置并重试。这将使您的服务器在开发模式下运行良好,并在生产中稳定运行。

【问题讨论】:

  • 问题确实是服务器为什么发送 RST 请求。客户端必须重置连接并通知'Connection reset by peer'消息。所以我认为你在正确的轨道上

标签: python sockets wsgi httplib2 werkzeug


【解决方案1】:

我遇到了同样的问题,但是使用 python-requests 客户端上传一个非常大的文件到 nginx+uwsgi 后端。

最终的原因是后端对上传的最大文件大小的上限低于客户端尝试发送的大小。

这个错误从未出现在我们的 uwsgi 日志中,因为这个限制实际上是 nginx 强加的。

在 nginx 中提高限制消除了错误。

【讨论】:

  • 天啊,到处搜索后我发现“内容长度”可能是此错误的根本原因
【解决方案2】:

我遇到过这个问题。见The Python "Connection Reset By Peer" Problem

您(很可能)遇到了基于 Python 全局解释器锁的小时间问题。

您可以(有时)通过战略性地放置time.sleep(0.01) 来纠正此问题。

“在哪里?”你问。难倒我了。这个想法是在客户端请求中和围绕客户端请求提供一些更好的线程并发性。尝试将其放在之前您发出请求,以便重置 GIL 并且 Python 解释器可以清除任何待处理的线程。

【讨论】:

  • 在链接中,问题似乎在于在同一进程中运行服务器和客户端。因此,他们受制于 gil。
  • 是的,但是...您会看到即使在不同的客户端-服务器主机中,相同的连接也会重置。我仍然认为你应该到处乱睡,看看线程调度的改变是否有帮助。
【解决方案3】:

不要将 wsgiref 用于生产。使用 Apache 和 mod_wsgi,或其他。

我们继续看到这些连接重置,有时是频繁的,使用 wsgiref(werkzeug 测试服务器使用的后端,可能还有 Django 测试服务器等其他服务器)。我们的解决方案是记录错误,循环重试调用,并在十次失败后放弃。 httplib2 尝试了两次,但我们需要更多。它们似乎也成束出现 - 增加 1 秒的睡眠时间可能会解决问题。

在通过 Apache 和 mod_wsgi 运行时,我们从未见过连接重置。我不知道他们有什么不同,(也许他们只是掩盖了他们),但他们没有出现。

当我们向本地开发社区寻求帮助时,有人确认他们看到许多使用 wsgiref 的连接重置在生产服务器上消失了。那里有一个错误,但很难找到它。

【讨论】:

    【解决方案4】:

    通常情况下,如果您执行不逗留的关闭操作(即,如果尚未发送和 ACK 的数据可以被堆栈丢弃),您将获得 RST;如果您执行正常的 FIN允许关闭逗留(即关闭等待传输中的数据被确认)。

    也许您需要做的就是将您的套接字设置为 linger,以便消除在套接字上完成的非延迟关闭和 ACK 到达之间的竞争条件?

    【讨论】:

      猜你喜欢
      • 2022-12-06
      • 1970-01-01
      • 2018-08-15
      • 2022-11-02
      • 2019-02-02
      • 2020-01-15
      • 1970-01-01
      • 2019-03-29
      • 2013-03-13
      相关资源
      最近更新 更多