sdlqzql 发表于 2016-8-31 18:02:16

java程序中关闭socket出现socket closed异常求助

我使用tomcat服务器跑javaweb应用,客户端会使用tcp连接服务器,服务器使用socket监听9014端口从而获取来自客户端数据。
同时,我还想通过客户端发送心跳包的方式维持长连接,服务器上使用timer来每隔一段时间对变量自加,当超过某个数时则认为接收客户端心跳包超时,此时服务器关掉socket。
但是,在定时器中关掉socket会报异常,异常如下所示:
      java.net.SocketException: Socket closed
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:150)
        at java.net.SocketInputStream.read(SocketInputStream.java:121)
        at java.net.SocketInputStream.read(SocketInputStream.java:107)
        at my.start.AutoStart$SocketTherad.run(AutoStart.java:111)

我的服务器代码如下所示:

package my.start;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

//创建AutoStart类,让他实现ServletContextListener(服务程序上下文监听器)接口
//实现ServletContextListener接口需要重写contextDestroyed()和contextInitialized()两个方法
//记得要在web.xml文件中加入
//   <listener>
//       <listener-class>my.test.AutoStart</listener-class>
//   </listener>
//这样,tomcat在启动时,就会同时调用该接口的contextInitialized()方法
//在contextInitialized()方法中,开启一个线程,用soket监听一个端口,从而实现TCP通信
public class AutoStart extendsHttpServlet{       

        private static final long serialVersionUID = 1L;
        private int soketPort = 9014;//要监听的服务器端口,可以根据需要进行修改
        @Override
        public void init() throws ServletException {
                // TODO Auto-generated method stub
                super.init();
                new MyThread().start();//创建一个MyThread线程对象,并启动线程
                System.out.println("开启监听线程");
        }
       
       
        //创建MyThread类,继承Thread方法
   class MyThread extends Thread
   {
       //重写Thread类的run()方法,用来实现MyThread线程的功能
         public void run()
         {
               //System.out.println("测试开始");
               try {
                                                ServerSocket ss = new ServerSocket(soketPort);
                                                System.out.println("监听到"+(soketPort+"")+"端口");
                                                while(true){
                                                        //System.out.println("已经创建soket");
                                                        //ss对象的accept()方法可以监听指定端口有没有TCP连接
                                                        //在没有TCP连接之前程序将阻塞在这里
                                                        Socket socket = ss.accept();
                                                        System.out.println("有客户端接入");
                                                        //监听到指定端口有TCP连接后,创建soket对象,程序不再堵塞,往下执行
                                                        //创建一个线程,去监听客户端通过TCP发来的数据
                                                        Thread sockThread=new SocketTherad(socket);
                                                        //启动线程
                                                        sockThread.start();
                                        }
                                } catch (IOException e) {
                                        // TODO Auto-generated catch block
                                        e.printStackTrace();
                                }
         }
   }
   int timeNum;
        class SocketTherad extends Thread{//继承Thread类来创建线程
                Socket socket;
                InputStream is;
                OutputStream os;
                boolean run_flag=true;//控制run()函数是否继续运行标志位
               
                Timer heartBeatTimer = new Timer(); //心跳包定时器
                private void startHeartBeatThread() {
                        timeNum=0;
                        TimerTask heartBeatTask = new TimerTask() {
                                public void run() {                      
                                        timeNum++;   
                      System.out.println("timerNum="+(timeNum+""));       
                      if(timeNum==2){//超时则关闭socket连接及定时器
                                                try {
                                                        is.close();
                                                        os.close();//关闭输出流
                                                        socket.close();//关闭soket
                                                        run_flag=false;//跳出死循环
                                                        System.out.println("TCP连接断开");       
                                                        heartBeatTimer.cancel();//关闭定时器
                                                } catch (IOException e) {
                                                        // TODO Auto-generated catch block
                                                       
                                                        e.printStackTrace();
                                                }
                      }
                                }
                        };
                        heartBeatTimer.schedule(heartBeatTask, 10*1000, 10*1000);
                }
               
                publicSocketTherad(Socket socket) {
                        this.socket = socket;//传递过来的soket参数赋予给socket对象
                }
               
                public void run() {//run()函数用来实现线程要完成的任务
                        startHeartBeatThread();
                        while(run_flag)
                        {
                                try {
                                        String str = null;
                                        is = socket.getInputStream();//获取输入流
                                        os=socket.getOutputStream();
                                        byte[] buffer = new byte;//数据缓冲区;
                                        int length=0;

                                        length = is.read(buffer);//读取接收到的数据流长度
                                       
                                        if(length != (-1)){//不是-1,说明读取到有效的数据
                                                str = new String(buffer,0,length);//输入流转换成str字符串                                               
                                                System.out.print("收到数据:");
                                                System.out.println(str);
                                        }
                                        else if(length == (-1)){//接收到数据长度为-1,说明客户端主动关闭了TCP连接
                                                is.close();//关闭输入流
                                                os.close();//关闭输出流
                                                socket.close();//关闭soket
                                                run_flag=false;//跳出死循环
                                                System.out.println("TCP连接断开");       
                                        }                                       
                                        buffer = null;
                                        System.gc();//垃圾回收
                                } catch (IOException e) {
                                        System.out.print("这里异常");

                                        e.printStackTrace();
                                }       
                        }
                }
        }

}

我通过单步执行发现,异常是在程序执行timeNUm变量等于2中的代码时产生
页: [1]
查看完整版本: java程序中关闭socket出现socket closed异常求助