"Connection reset" 使用 SOAP 时

"Connection reset" when using SOAP

我有一个 REST 服务,一些客户端收到 "Connection reset" 错误。但是 SOAP 是无状态的,那么它为什么不简单地重新连接并重新发送请求呢?它实际上在我的用例中发送了多条消息,但第一个失败了,那只是为了从服务器获取一些配置数据。这是我需要配置的东西吗?客户端是否应该以编程方式尝试重新发送消息?部分用户多次尝试,结果相同。

过去几年从未发生过,但现在我收到了一些关于此问题的报告。
客户端在 javax.xml.ws.Service 的实现中使用,而不仅仅是原始套接字。但即使我使用 JAX,我也会遇到低级错误。它由 WebServiceException 包裹,但这并不能真正帮助我解决这个问题。 客户端都使用 Java 8。它是 Update 66 或 Update 74。

我自己无法重现问题,我只有来自用户的日志文件。

这是完整的堆栈跟踪:

javax.xml.ws.WebServiceException: java.net.SocketException: Connection reset
    at com.sun.xml.internal.ws.transport.http.client.HttpClientTransport.readResponseCodeAndMessage(Unknown Source)
    at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.createResponsePacket(Unknown Source)
    at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.process(Unknown Source)
    at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.processRequest(Unknown Source)
    at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(Unknown Source)
    at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Unknown Source)
    at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Unknown Source)
    at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Unknown Source)
    at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Unknown Source)
    at com.sun.xml.internal.ws.client.Stub.process(Unknown Source)
    at com.sun.xml.internal.ws.client.sei.SEIStub.doProcess(Unknown Source)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
    at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(Unknown Source)
    at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(Unknown Source)
    at com.sun.proxy.$Proxy31.getLimits(Unknown Source)
    at xxxxxxxxxxxxx.SOAPServerAdapter.connect(Unknown Source)
    at xxxxxxxxxxxxxxxxxxxx(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(Unknown Source)
    at java.net.SocketInputStream.read(Unknown Source)
    at sun.security.ssl.InputRecord.readFully(Unknown Source)
    at sun.security.ssl.InputRecord.read(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at sun.security.ssl.SSLSocketImpl.readDataRecord(Unknown Source)
    at sun.security.ssl.AppInputStream.read(Unknown Source)
    at java.io.BufferedInputStream.fill(Unknown Source)
    at java.io.BufferedInputStream.read1(Unknown Source)
    at java.io.BufferedInputStream.read(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
    at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
    at java.net.HttpURLConnection.getResponseCode(Unknown Source)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
    ... 18 more

检查服务器的负载。看起来服务器由于负载而正在关闭连接 - exception on web-service call

原来是关于IPv4和IPv6的。我没有足够的知识来给出完美的答案,但我可以 post 这里他们告诉我的。也许这可以帮助其他 devs/users 遇到同样问题的人。

所以有些客户端会意外重置连接,这与通常情况下的服务器负载无关。

如果客户端的 ISP 试图摆脱 IPv4,他们会给每个用户一个唯一的 IPv6 地址(请注意,ISP 可能会逐渐这样做)。除了本地使用的 IPv4 之外,他们实际上不再为每个客户端分配 IPv4 地址,因为大多数人仍然在其 LAN 中使用 192.168.0.0/24 之类的地址。

他们使用一些 transaction mechanism(例如 Dual-Stack Lite)而不是经典的 IPv4。这些客户端无法直接访问 IPv4 互联网。因此,如果您的服务器仅支持 IPv4,那么他们可能会遇到与使用代理时遇到的类似问题。它们将 IPv4 数据包封装在 IPv6 数据包中以用于某些通信部分。来自维基百科:"The original IPv4 packet is recovered and NAT is performed upon the IPv4 packet and is routed to the public IPv4 Internet."

我真的不知道这里出了什么问题。也许 NAT 用完了地址/端口或类似的东西。或者该过程花费的时间太长,连接被通信中涉及的某个节点重置。

所以有两件事要做:

  1. 将这些问题通知 ISP。他们可能会帮助您追踪确切的问题并帮助他们的客户,以便他们可以使用您的服务。为此,您需要知道有 "connection reset" 问题的用户的 ISP。将它们发送到 https://www.whoismyisp.org/ 或类似网站。
  2. 尽快升级到IPv6。您的服务器可以同时使用两个版本的协议。