104、“连接由对等方重置”套接字错误,或关闭套接字何时会导致 RST 而不是 FIN?

StackOverflow https://stackoverflow.com/questions/383738

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

(104, 'Connection reset by peer')

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

  • 由于 OAuth 标头的大小,请求被分成两个数据包。服务用 ACK 响应两者
  • 该服务发送响应,每个标头一个数据包(HTTP/1.0 200 OK,然后是日期标头等)。客户端用 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,“连接由对等方重置”))。所以,看起来它是在 Linux 上运行的服务。是 x86_64 吗?一个糟糕的 glibc?wsgiref?还在寻找...

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

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

有帮助吗?

解决方案

我遇到过这个问题。看 Python“对等方重置连接”问题.

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

你可以(有时)用以下方法纠正这个问题 time.sleep(0.01) 战略性地放置。

“在哪里?”你问。打败我。这个想法是在客户端请求中和周围提供更好的线程并发性。尝试把它只是 您发出请求,以便重置 GIL,并且 Python 解释器可以清除任何挂起的线程。

其他提示

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

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

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

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

我知道您正在使用 python,但我发现这篇 Java 文章很有用。

http://java.sun.com/javase/6/docs/technotes/guides/net/articles/connection_release.html

通常,如果您进行了一次不会持续的关闭(即如果数据尚未发送和确认,则堆栈可以丢弃数据,如果允许关闭延迟(即,关闭等待传输中的数据被确认)。

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

然而,我在使用 python-requests 客户端发布到 nginx+uwsgi 后端上传非常大的文件时遇到了同样的问题。

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

该错误从未出现在我们的 uwsgi 日志中,因为此限制实际上是由 nginx 施加的。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top