话说Connect reset异常

本文详细解析了Solr在Tomcat部署环境下遇到的ConnectionReset异常问题,通过分析TCP/IP原理及Oracle文章,揭示了异常关闭场景导致此现象的原因。文章深入探讨了HTTP客户端在连接池管理下的行为,以及如何正确处理关闭连接以避免RST报文的产生。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     起因是这样的,线上log经常出现Connection Reset异常,从堆栈上分析是solr进行sharding request时发生的,solr部署在tomcat上。从现场来看,原因很明白Server端发出RST包。但具体原因是什么就得经过一番分析了,

    经过google百度以及和网友沟通,发现会有以下场景导致RST:
    1. 设置SoLinger,并设置停留时间为0
     显然不是这样的场景,如是则会经常出现,而不是偶尔出现。还有其他的吗?我翻看了一下TCP/IP详解,TCP的连接与终止以及复位报文段。有点收获但还是没有看太懂,呵呵答案就在书上,也许没有沉下心去,一开始并没有书上介绍套出问题的场景。后来看到oracle的一篇文章 http://docs.oracle.com/javase/1.5.0/docs/guide/net/articles/connection_release.html.
发现异常关闭非常适合出现问题的场景。啥叫异常关闭呢,正常的close是四次挥手
例如客户端执行close的时候,发出FIN,告诉对端我不再接受和发送数据,而对端也应该由应用程序调用close结束链接,也许你会说发出FIN只是告诉对端不再发送数据还能接收数据,事实上也是可以的,这样的关闭叫做半关闭,通过调用shutdown方法来实现。
   solr为什么会遇到这样的问题,httpclient为了减少链接的建立开销使用connection manager的连接池管理链接,我们知道虽然Http1.1支持keep alive,但仍有条件限制,例如keepalivetimeout以及keepalive的个数。当tomcat进行keepalive的connectin timeout处理的处理的,只是单方面的close,对端趟在连接池中的connection并不知道也不会执行相应的close,恰巧这时候有一个reuest使用这个connection发出请求,这一点特别重要,还是能发送数据的,最初的时候我以为服务端close了客户端就不能再使用conneciton发送数据了。服务端不会读取client端发过来的数据坚决执行关闭,这时候这个关闭就是RST而不是FIN了。
B's TCP stack knows that some data is effectively lost and it will forcibly terminate with RST rather than use the orderly  FIN  procedure.
   有两种这样的场景:
   1. A向B 发送数据,B的应用执行close,而这时A试图继续发而不是由应用调用close。
   2. A向B发送数据,B不做任何处理,不读取任何数据坚决地close,这时候这个close发的就是RST。
   我写了一段代码来模拟以上两种情况
Server
public static void run(){
                try{
                        //InetSocketAddress address = new InetSocketAddress("10.58.99.27", 9090);
                    //InetAddress address =     InetAddress.getByName("10.58.99.27");
            ServerSocket serverSocket = new ServerSocket(9090,1);
            ExecutorService threadPool = Executors.newCachedThreadPool();
//            for(int i = 0; i < 1;i++){
//              new Thread(new BioHttpServer.Connector()).start();
//            }
//            latch.countDown();
            while(true){
                   Socket client = serverSocket.accept();
                   Thread.sleep(1000);//调整这个时间 如调整为100 则为情况1 1000为情况2
                   client.close();
                 //  client.shutdownOutput();
//                   if(isDistribute){
//                         threadPool.execute(new SocketProcessor(client));
//                   }else{
//                         new SocketProcessor(client).run();
//                   }
    
            }   
    
        }catch(Exception e){ 
            e.printStackTrace();
        }finally{
    
        }   
        }  
 Client
try {
                        Socket client = new Socket("10.58.99.74", 9090);
                        //      client.setSoTimeout(5000);
                                System.out.println(client);
                                InputStream ins =client.getInputStream();
                                int i = 0;
                //              System.out.println(ins.read());
                                while(i++ < 100000){
                                   client.getOutputStream().write(64);
                                }   
                                System.out.println(ins.read());
                } catch (UnknownHostException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }   
 


Java中捕获connect reset异常,首先需要了解connect reset异常的情况。connect reset异常通常是在网络连接过程中发生的,当客户端试图连接到服务器端时,如果服务器端运行异常、断网或者网络延迟过高等情况都可能导致connect reset异常的发生。 要捕获connect reset异常,可以使用try-catch语句块来处理异常。在进行网络连接的代码块中,使用try关键字将可能发生connect reset异常的代码包围起来,在catch块中处理具体的异常情况。 下面是一个简单的示例代码,演示了如何捕获connect reset异常: ``` import java.io.IOException; import java.net.Socket; public class ConnectionExample { public static void main(String[] args) { String serverName = "localhost"; int port = 8080; try { Socket socket = new Socket(serverName, port); // 进行网络通信的逻辑... socket.close(); // 关闭socket连接 } catch (IOException e) { if (e instanceof java.net.SocketException && e.getMessage().equals("Connection reset")) { System.out.println("连接被重置。"); } else { System.out.println("发生其他IO异常:" + e.getMessage()); } } } } ``` 在上述代码中,我们使用了一个Socket对象来进行连接操作。在try代码块中,我们通过调用`Socket`类的构造方法来建立与服务器的连接。如果连接过程中发生connect reset异常,则会抛出`java.net.SocketException`异常,并且异常的具体信息是"Connection reset"。通过检查异常的类型和错误信息,我们可以判断是否是连接被重置的情况,从而进行相应的处理。 当捕获到connect reset异常时,可以根据具体的业务需求进行处理。比如,可以重新建立连接、记录日志等操作。在catch代码块中,我们使用了条件判断语句来判断异常类型和错误信息,以便更精确地处理connect reset异常。 总之,捕获connect reset异常可以帮助我们更好地处理网络连接过程中可能遇到的问题,提高程序的健壮性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值