【问题标题】:Java Socket Exception: Socket Closed and null valueJava 套接字异常:套接字已关闭且值为空
【发布时间】:2014-07-30 09:08:49
【问题描述】:

我想创建一个可以与多个客户端连接的服务器,但是我总是得到'Socket Closed'异常或从输入流中读取NULL值,以前我认为这是由于以错误的方式关闭套接字连接引起的,所以我发布了这个topic,但现在看来这不是问题。

服务器方法

//here I use thread pool to solve concurrency issue
public static void main(String[] args) {

 try{
   ExecutorService service = Executors.newFixedThreadPool(4);
   ServerSocket serverSocket = new ServerSocket();

   while (true) {
      //keep listening
      Socket socket = serverSocket.accept();
      service.execute(new HandlerThread(socket));
   }
  }catch(Exception ex){
     ex.printStackTrace();
  }
}

HandlerThread 类

public class HandlerThread extends Thread{

    private Socket socket;
    private BufferedReader in;

    public HandlerThread(Socket socket) throws IOException {
        this.socket = socket;
        this.start();
    }

    public void run(){

        try {
            //Caches is a singleton class, which used to store the received data from client
            Caches caches = Caches.getInstance();

            //32 line
            in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
            String line = in.readLine();

            //caches.list is an ArrayList
            synchronized (caches.globalCaches) {
                if (null != line) {
                    caches.globalCaches.add(line);
                }
            }

            System.out.println(line);

            in.close();
            socket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

客户端模拟器

public class Main {

    public static void main(String[] args) throws IOException, InterruptedException {

        for(int i = 0 ; i < 40; i++){
            Thread.sleep(2000);
            test test1 = new test();
            test1.start();
        }
    }

    public static class test extends Thread{

        public void run(){
            try {
                Socket socket = new Socket("localhost", 5050);

                PrintStream out = new PrintStream(socket.getOutputStream());
                out.println("Hello Server!");

                out.close();
                socket.close();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

异常和问题

在客户端模拟器之前启动服务器,客户端模拟器没有任何异常,但是在服务器端,并没有收到所有数据,从控制台打印信息中,我看到'null','Hello Server','java. net.SocketException: Socket is closed...',如下所示

Hello Server
null
null
Hello Server
java.net.SocketException: Socket is closed
Hello Server
    at java.net.Socket.getInputStream(Socket.java:876)
    at com.icubeidea.core.threads.HandlerThread.run(HandlerThread.java:32)
Hello Server

我研究了很长时间,仍然找不到到底是什么导致了这些异常和数据丢失的问题,还有可能导致服务器运行一段时间后出现内存泄漏问题的潜在风险?

【问题讨论】:

  • 可能是因为您在线程上调用 start() 的方式。改用service.execute(new HandlerThread(socket).start()); 并从HandlerThread 构造函数中删除this.start()
  • "尝试 service.execute(new HandlerThread(socket).start());" ——不啊啊啊啊!!!这是一个双重错误!幸运的是它甚至不会编译。
  • @user3811473 你的怀疑是正确的,但是解决方法是错误的,正如 Hanno 所说,它甚至不会被编译。
  • @Z.Neeson,是的,我意识到为时已晚,通常它会起作用,但由于线程被传递给执行器,它接受一个线程对象,然后不能在那里调用 start :) 我没有测试它,这就是为什么我没有把它写成答案:)
  • @user3811473 同意。如果没有执行器,建议不要从其构造函数中启动线程。

标签: java multithreading sockets


【解决方案1】:

问题似乎出在您的HandlerThread 的构造函数中:

你打电话给this.start();,你真的不应该。尤其是同时使用ExecutorService 时!

(在这种特定情况下,您正在创建一个新线程并start() 它同时告诉您的执行程序运行相同的代码。最后,相同的代码将运行两次 /em> 在单个套接字上,这可能会导致各种问题,并且其中一个线程将关闭套接字,而另一个线程仍在尝试从中读取。这就是异常的实际来源。)

解决方案:

不要扩展 Thread,而是让您的 HandlerThread 只实现 Runnable 接口。

一旦你将该类的一个实例交给执行器,它就会负责运行你的run() 方法;无需自己启动任何线程。

【讨论】:

  • 服务器运行一段时间后,您是否发现任何可能导致内存泄漏问题的潜在风险?
  • 您必须以某种方式限制caches.globalCaches 的大小。为了确保,我会在 finally 块中关闭套接字:try { ... } finally { socket.close(); }。这样,即使在处理数据期间发生异常,套接字也会关闭/释放。您可能还想设置timeout 以防止服务器线程无限期卡住,以防客户端不发送任何(更多)数据。
猜你喜欢
  • 2014-03-01
  • 1970-01-01
  • 2014-09-09
  • 1970-01-01
  • 2023-03-03
  • 2017-07-18
  • 2011-05-28
  • 1970-01-01
  • 2013-11-02
相关资源
最近更新 更多