Java 服务端 socket 掉线重启后,客户端自动重连

目的

强调:setSoTimeout()函数的重要性,目的是为了写出更健壮的程序。

问题:如果客户端发起的socket 在连接后,读取数据流之前,刚好服务器端突然断线了,紧接着又重启了,则当前socket连接,容易死锁,从而整个客户端程序停滞。

一般网上的思路,都是要判断服务端的状态、发送心跳包什么之类的,我个人认为这些操作比较繁琐、也不一定有效,经过多番摸索,终于明白了函数socket.setSoTimeout() 的重要性:

方法

1)使用socket 短连接

2)  启用 socket 的 setSoTimeout()的方法,以及ConnectTimeout() 连接超时。

3)捕捉异常:java.net.SocketTimeoutException: Read timed out后,重新开启一个socket。

具体代码如下:

            try {
                // 并将其连接到指定主机上的指定端口号
                while (true) {    // Java里Socket的循环往复使用 https://www.pianshen.com/article/58251192706/

                    socket = new Socket(); //使用socket 短连接
                    socketAddress = new InetSocketAddress(ip, port);
                    //socket.setKeepAlive(true);
                    socket.connect(socketAddress, 2*1000);//设置超时为20秒
                    socket.setSoTimeout(3*1000);//设置读操作超时时间 3 s,
                    //这样才能捕捉异常:java.net.SocketTimeoutException: Read timed out,非常重要,否则
                    //当在连接伤后,刚好服务器器socket server断开,则直接运行下面语句中的readLine()会死锁

                    out = new PrintStream(socket.getOutputStream());
                    out.println("push message...");// 向服务器端发送数据

                    // 读取服务器端数据
                    br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

                    ret = br.readLine();
                    releaseResource(br ,out, socket);

                    if( ret == null ){
                        break;
                    }

                    Thread.sleep(1 * 1000);

                }
            } catch (Exception e) {
                System.out.println("--- socket连接error-----------");
                e.printStackTrace();
            } finally {
                releaseResource(br ,out, socket);

                try {
                    Thread.sleep(3 * 1000); //必须要 等待一定的秒数,等远端的socket server在足够时间内,启动起来,再尝试重连。
                } catch (Exception e) {
                }
                System.out.println("- - - finally语句中,socket server断开后,开始重连-----------\n\n");
            }
        }

上面代码,如果刚好在执行br = new BufferedReader(n。。。之后,执行语句ret = br.readLine() 之前,刚好服务端的socket service断掉、并瞬间快速重启了,那么之前的建立的socket TCP/IP就其实是个死的TCP/IP连接,这个时候执行 readLine()语句就会timeout死锁,程序停滞,如果前面,没有,设置setSoTimeout(),那么这个异常就不会,被捕捉到,从而一直停在语句readLine()那里死锁下去。那这个不是我们期望的,当前socket发送来的数据,丢失了也就算了;后续的要能正确接受、保存。

如果前面设置了socket.setSoTimeout(3*1000),就会在3秒内,捕捉到这个异常,从而放弃这个socket,进入重连。重连后,由于通道中会继续存在先前死的TCP/IP连接,可能会再次报告SocketTimeoutException异常,但是不要急(欲速则不达),经过几次反复重连后,服务器系统会重新开辟一个新的TCP/IP连接,回收老的、有问题的TCP/IP连接,整个重连就彻底变正常了。

---------------------------------

参考: java.net.SocketTimeoutException: Read timed out报警_summer089089的博客-CSDN博客

connect timeout 是建立连接的超时时间;
read timeout, 是传递数据的超时时间。
ConnectTimeout只有在网络正常的情况下才有效,而当网络不正常时,ReadTimeout才真正的起作用,即IdIOHandlerStack 里的 WaitFor 是受ReadTimeout限制的,因此,这2个属性应该结合实用。

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值