【问题标题】:java.net.SocketException: Connection resetjava.net.SocketException:连接重置
【发布时间】:2010-09-08 22:35:46
【问题描述】:

我在尝试从套接字读取时收到以下错误。我在那个InputStream 上做一个readInt(),我收到了这个错误。仔细阅读文档,这表明连接的客户端部分关闭了连接。在这种情况下,我是服务器。

我可以访问客户端日志文件并且它没有关闭连接,事实上它的日志文件表明我正在关闭连接。那么有人知道为什么会这样吗?还有什么要检查的?当本地资源可能达到阈值时,是否会出现这种情况?


我确实注意到我有以下行:

socket.setSoTimeout(10000);

就在readInt() 之前。这是有原因的(长篇故事),但只是好奇,是否存在可能导致指示错误的情况?我在我的 IDE 中运行服务器,我碰巧让我的 IDE 卡在断点上,然后我注意到完全相同的错误开始出现在我自己的 IDE 日志中。

无论如何,只是提一下,希望不是红鲱鱼。 :-(

【问题讨论】:

  • 你有来自双方的堆栈跟踪吗?你能再描述一下网络架构吗? (通过狂野的互联网?在同一台机器上?介于两者之间?)它是否一直发生?还是间歇性的?
  • 我在使用 WAMP 时遇到了同样的问题,但在远程服务器上修复了它。

标签: java sockets networking connection socketexception


【解决方案1】:

有几种可能的原因。

  1. 另一端故意重置连接,我不会在这里记录。应用软件很少这样做,而且通常是不正确的,但对于商业软件来说却不是未知数。

  2. 更常见的情况是,写入连接的另一端已经正常关闭。换句话说,应用程序协议错误。

  3. 也可能是socket接收缓冲区中有未读数据时关闭socket造成的。

  4. 在 Windows 中,“软件导致连接中止”与“连接重置”不同,是由您端发送的网络问题引起的。有一篇关于此的 Microsoft 知识库文章。

【讨论】:

  • @MattLyons 谢谢。有比这更好的 MSDN 文章。坦率地说,我觉得这很难相信。在建立正确的源 IP 地址和目标 IP 地址之前,连接甚至都不存在。我看到的 MSDN 文章提到了持久性网络错误超时连接。
  • 鉴于你的前 3 分,this 十年后你会很感兴趣
  • @zanderwar 谢谢。那里抄袭比比皆是。
【解决方案2】:

连接重置仅仅意味着收到了 TCP RST。当您的对等方收到无法处理的数据时,就会发生这种情况,这可能有多种原因。

最简单的方法是关闭套接字,然后在输出流上写入更多数据。通过关闭套接字,您告诉您的对等方您已完成通话,它可以忘记您的连接。无论如何,当您在该流上发送更多数据时,对等方会使用 RST 拒绝它,让您知道它没有在监听。

在其他情况下,干预防火墙甚至远程主机本身可能会“忘记”您的 TCP 连接。如果您长时间不发送任何数据(2 小时是常见的超时),或者因为对等方重新启动并丢失了有关活动连接的信息,则可能会发生这种情况。在这些失效连接之一上发送数据也会导致 RST。


更新以响应更多信息:

仔细查看您对SocketTimeoutException 的处理。如果在套接字操作上阻塞时超过了配置的超时,则会引发此异常。抛出此异常时,套接字本身的状态不会改变,但如果您的异常处理程序关闭套接字,然后尝试写入它,您将处于连接重置状态。 setSoTimeout() 旨在为您提供一种干净的方法来摆脱 read() 操作,否则可能会永远阻塞,而不会做诸如从另一个线程关闭套接字之类的肮脏事情。

【讨论】:

  • 在几个方面都不正确。垃圾收集和进程退出都会导致适当的关闭,而不是重置,但关闭后由对等方写入可能会导致重置而不是 EOS。仅当阅读器设置了读取超时时才会引发 SocketTimeoutExceptions。
  • 这并不总是意味着收到了 RST。这也可能意味着一个是由这一方生成的。
  • 而且您不能写入已关闭的套接字。您将获得SocketException: socket closed,而对等方将不会获得 RST。答案完全错误。
【解决方案3】:

每当我遇到类似这样的奇怪问题时,我通常会使用WireShark 之类的工具坐下来查看来回传递的原始数据。您可能会对断开连接的地方感到惊讶,并且只有在您尝试阅读时才会通知

【讨论】:

    【解决方案4】:

    你应该非常仔细地检查完整的痕迹,

    我有一个服务器套接字应用程序并修复了 java.net.SocketException: Connection reset 案例。

    在我的情况下,它发生在从 clientSocket Socket 对象读取时,该对象由于某种原因关闭了其连接。 (网络丢失、防火墙或应用程序崩溃或有意关闭)

    实际上,当我从这个 Socket 对象中读取错误时,我正在重新建立连接。

    Socket clientSocket = ServerSocket.accept();
    is = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    int readed = is.read(); // WHERE ERROR STARTS !!!
    

    有趣的是for my JAVA Socket 如果客户端连接到我的ServerSocket 并关闭其连接而不发送任何内容is.read() 被重复调用。似乎是因为在无限循环中从这个套接字读取你尝试从关闭的连接中读取。 如果您使用类似下面的内容进行读取操作;

    while(true)
    {
      Receive();
    }
    

    然后你会得到一个类似下面的stackTrace

    java.net.SocketException: Socket is closed
        at java.net.ServerSocket.accept(ServerSocket.java:494)
    

    我所做的只是关闭 ServerSocket 并更新我的连接并等待进一步传入的客户端连接

    String Receive() throws Exception
    {
    try {                   
                int readed = is.read();
               ....
    }catch(Exception e)
    {
            tryReConnect();
            logit(); //etc
    }
    
    
    //...
    }
    

    这会在未知客户端套接字丢失时重新建立我的连接

    private void tryReConnect()
            {
                try
                {
                    ServerSocket.close();
                    //empty my old lost connection and let it get by garbage col. immediately 
                    clientSocket=null;
                    System.gc();
                    //Wait a new client Socket connection and address this to my local variable
                    clientSocket= ServerSocket.accept(); // Waiting for another Connection
                    System.out.println("Connection established...");
                }catch (Exception e) {
                    String message="ReConnect not successful "+e.getMessage();
                    logit();//etc...
                }
            }
    

    我找不到其他方法,因为正如您从下图中看到的那样,如果没有 try and catch,您将无法理解连接是否丢失,因为一切似乎都是正确的。我在不断收到Connection reset 时收到了这张快照。

    【讨论】:

    • @MarquisofLorne 是的,正确,这就是为什么该例程处于另一个 while 循环中的原因。
    • @MarquisofLorne 在阅读我自己的答案后我注意到它需要“被反复调用”。感谢您指出。 5年前:)。我现在实际上改进了它,基于读取-1,添加超时异常等。不正常的连接断开仍然是问题,人们遵循不同的不活动管理方法。
    【解决方案5】:

    说起来很尴尬,但是当我遇到这个问题时,我在读取所有数据之前关闭连接只是一个错误。在返回小字符串的情况下,它可以工作,但这可能是因为在我关闭它之前,整个响应都被缓冲了。

    如果返回的文本量较长,则会引发异常,因为返回的缓冲区更多。

    您可以检查是否存在这种疏忽。请记住,打开 URL 就像打开文件一样,请务必在完全读取后将其关闭(释放连接)。

    【讨论】:

      【解决方案6】:

      我有同样的错误。我现在找到了问题的解决方案。问题是客户端程序在服务器读取流之前完成。

      【讨论】:

      • 这本身不会导致此异常。
      • 如果 System.exit(0) 杀死程序并且没有人调用 socket.close() 因为连接处于错误状态并且没有正确关闭,它会。更恰当地说,他有一个客户端程序在不关闭套接字的情况下关闭;)这是一件坏事,应该修复。
      • @DeanHiller 不,不会。操作系统会以与应用程序相同的方式关闭套接字。
      • @EJP ....我不确定...我只知道我们可以用 System.exit 重现它,但我不记得操作系统/配置,因为那是很久以前的事了。 ...在服务器上调用 socket.close() 阻止了连接重置并且它的行为更正常。
      • @DeanHiller reading 进程在写入过程完成写入之前退出。
      【解决方案7】:

      我在使用 Java 编写的 SOA 系统时遇到了这个问题。我在不同的物理机器上同时运行客户端和服务器,它们工作了很长时间,然后那些讨厌的连接重置出现在客户端日志中,服务器日志中没有任何奇怪的东西。重新启动客户端和服务器并没有解决问题。最后我们发现服务器端的堆已经满了,所以我们增加了 JVM 可用的内存:问题解决了!请注意,日志中没有 OutOfMemoryError:内存只是稀缺,没有耗尽。

      【讨论】:

      • 问题中没有关于OutOfMemoryError 的内容。
      • 是的,我知道,我没有说别的。
      【解决方案8】:

      检查您的服务器的 Java 版本。发生在我身上是因为我的 Weblogic 10.3.6 在 TLSv1 上的 JDK 1.7.0_75 上。我尝试使用的其余端点正在关闭 TLSv1.2 以下的任何内容。

      默认情况下,Weblogic 试图协商最强的共享协议。在此处查看详细信息:Issues with setting https.protocols System Property for HTTPS connections

      我添加了详细的 SSL 日志记录来识别支持的 TLS。这表明 TLSv1 正在用于握手。
      -Djavax.net.debug=ssl:handshake:verbose:keymanager:trustmanager -Djava.security.debug=access:stack

      我通过将该功能推送到我们的 JDK8 兼容产品来解决这个问题,JDK8 默认为 TLSv1.2。对于那些仅限于 JDK7 的用户,我还通过升级到 TLSv1.2 成功测试了 Java 7 的解决方法。我用了这个答案:How to enable TLS 1.2 in Java 7

      【讨论】:

      • 非常感谢,您为我指明了解决问题的新方向。最后我发现是这样的!!!
      • SSL 协议不匹配不会导致连接重置。它们会导致握手失败。
      【解决方案9】:

      Java 程序尝试通过 SSH 在服务器上发送命令时也遇到了这个问题。问题在于执行 Java 代码的机器。它没有连接到远程服务器的权限。 write() 方法运行良好,但 read() 方法抛出 java.net.SocketException: Connection reset。我通过将客户端 SSH 密钥添加到远程服务器已知密钥来解决此问题。

      【讨论】:

        【解决方案10】:

        在我的情况下是DNS problem
        我输入了host file解析的IP,一切正常。 当然这不是一个永久的解决方案,这让我有时间解决 DNS 问题。

        【讨论】:

          【解决方案11】:

          根据我的经验,我经常会遇到以下情况;

          1. 如果您在公司公司工作,请联系网络和安全团队。因为在向外部服务发出请求时,可能需要为相关端点授予权限。

          2. 另一个问题是运行您的应用程序的服务器上的 SSL 证书可能已过期

          【讨论】:

          • SSL 证书不会导致连接重置。
          【解决方案12】:

          我已经看到了这个问题。就我而言,在特定的 Java 类中重用相同的 ClientRequest 对象会导致错误。该项目使用的是Jboss Resteasy

          1. 最初只有一种方法是使用/调用对象 ClientRequest(作为类中的全局变量放置)在特定 URL 中执行请求。
          2. 之后,创建了另一个方法来使用另一个 URL 获取数据,但重用了相同的 ClientRequest 对象。

          解决方案:在同一个类中创建另一个 ClientRequest 对象,并且专门不被重用。

          【讨论】:

            猜你喜欢
            • 2021-03-10
            • 2022-01-18
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多