Java使用Socket网络编程,Socket连接不释放/发现大量TIME_WAIT/CLOSE_WAIT、服务器卡死等问题?看这篇就解决了!

填坑日记:

 1.Socket使用情况:

在Java项目中,服务器端使用了ServerSocket网络编程来处理各个C++客户端发送过来的数据。使用流程主要如下:

(1)程序启动时,开启一个线程进行socket监听;

ListenThread listenThread = new ListenThread(serverSocket);
Thread serverListenThread = new Thread(listenThread);
serverListenThread.start();

(2)在监听线程中,每当accept收到客户端连接,开启数据处理线程对数据进行处理,数据处理线程将持续接收客户端的数据进行处理,每当读取数据流完毕后,进行回复帧发送。

Socket socket = serverSocket.accept();  //接收客户端的连接
logger.debug("client socket size is:" + socket.getReceiveBufferSize());
SocketProcessThread socketProcessThread = new SocketProcessThread(socket); //创建socketProcessThread的实例对象
Thread serverSocketProcessThread = new Thread(socketProcessThread); //创建线程对象
serverSocketProcessThread.start(); //开启线程,执行其中的run()方法
ogger.info("Server start SocketProcessThread.");

其中,数据处理线程run方法如下:

@Override
    public void run() {

        BufferedReader br = null;   //读入数据缓冲流
        PrintWriter pw = null;   //下位机客户端——>服务器端

        try{
//            System.out.println(socket.getInputStream());
            br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"GBK"));
            pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),"UTF-8")));
            logger.debug(new Date() + "Server:connected, start receive data.");

            /*循环获取socket下位机发送过来的数据*/
            char[] cbuf = new char[1024];
            int len = 0;

            while(true){

                if((len = br.read(cbuf))!=-1) {
                    //未到达末尾
                    String receivedMsg = new String(cbuf,0,len);
                    logger.debug("The data is: " + receivedMsg);
                    logger.debug(new Date() + "Server:get a data.");
                    logger.debug(new Date() + "Server:start to analysis data.");

                    /*开始解析数据内容,并将数据保存至数据库*/
                    String replyString = AnalysisData(receivedMsg);

                    /*读取分析完毕,将回复帧写入*/
                    pw.print(replyString);
                    pw.flush();
                }
            }
        }catch (Exception e){

            System.out.println("Get socket InputStream Msg fail.");
            e.printStackTrace();
            e.getStackTrace();
        }finally {
            //在此关闭输入输出流、socket下位机连接
            try {
                br.close();
                pw.println(new Date() + "Server: socket connection close now.");
                pw.flush();
                pw.close();
                socket.close();
                logger.debug("current socket is closed!");
            } catch (IOException e) {
                logger.warn("One socket can't be close.");
                e.printStackTrace();
            }
        }

    }

 2.主要问题描述:

项目上线测试后,启动项目,刚开始socket数据交互反应速度很快,客户端访问Java后台服务器很快,所有服务一切正常。项目测试响应ok。服务器程序在服务器主机上,之后过了几天发现,客户端访问速度变慢了很多,持续测试,发现速度越来越慢直至没有响应。

3.找bug:

(1)使用XShell连接服务器查看日志发现:服务器可以正常接收数据,但是处理响应速度超级慢,光是读取socket数据处理已经达到s级了:

 (2)使用df -h查看主机资源使用情况,正常:

 (3)怀疑是端口占用,连接不释放导致响应慢的问题,使用netstat -ap查看端口占用情况:发现大量socket处于CLOSE_WAIT状态:

(4)使用  netstat -nat|grep -i "8082"|wc -l 统计端口占用数,发现上百。。。。且随着测试的增加,继续增加:

好吧,至此发现问题首先是代码上的bug:没有在对客户端关闭socket时关闭接收的socket。

4、问题解决:

(1)在代码中增加以下代码,对客户端socket状态进行监测,当客户端socket关闭时,主动关闭当前socket。

方法解释:方法sendUrgentData,它往输出流发送一个字节的数据,只要对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的。

try{
      //此用来检测客户端状态
      socket.sendUrgentData(0xFF);
}catch(Exception ex){
      //TODO:在此执行重连操作或关闭socket回收资源操作

}

5、验证:

(1)开启多个网络连接助手进行连接测试;

(2)使用netstat -nat|grep -i "8082"|wc -l命令查看端口连接数情况;

(3)结果:当关闭连接时,连接数减少;当增加连接时,连接数对应增加;则说明了服务端的socket连接已被正常释放回收,而不是被持续占用。

 问题解决!

 

 

 

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值