【问题标题】:(Java, Socket) BufferedReader blocks thread, unable to .close()(Java, Socket) BufferedReader 阻塞线程,无法 .close()
【发布时间】:2018-02-24 12:37:52
【问题描述】:

所以我为我的树莓派编写了一个客户端-服务器应用程序——为了处理服务器上的多个客户端,我总是为每个客户端套接字打开一个新的“ClientMessageListener”线程。

我试图创建一个销毁链,当我希望 ServerSocket 关闭时调用它。它遍历每个线程并调用 ClientMessageListener 的销毁方法,该方法应该关闭连接资源,然后关闭套接字本身。

我的客户端处理程序如下所示:

package com.imnos.piserver.server.serversocket.client;

import com.imnos.piserver.server.serversocket.ServerRequestController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
* @author simon
*/
public class ClientMessageListener implements Runnable {

    private static final ServerRequestController SRC
            = ServerRequestController.getInstance();

    private Socket clientSocket = null;

    private PrintWriter out = null;
    private InputStreamReader inputStream = null;
    private BufferedReader in = null;

    ClientMessageListener(final Socket clientSocket) {
        this.clientSocket = clientSocket;
        this.initDataStream();
    }

    /**
     * @return
     */
    synchronized boolean destroyClientMessageListener() {

        if (this.clientSocket == null) {
            return false;
        }

        if (this.in != null) {

            try {

                this.in.close(); // Method stucks here

            } catch (IOException ignore) {
                ignore.printStackTrace();
            } finally {
                this.in = null;
            }

        }

        if (this.inputStream != null) {

            try {

                this.inputStream.close();

            } catch (IOException ignore) {
                ignore.printStackTrace();
            } finally {
                this.inputStream = null;
            }

        }

        if (this.out != null) {

            this.out.close();
            this.out = null;

        }

        return true;
    }

    /**
     * @return
     */
    private synchronized boolean initDataStream() {

        if (this.clientSocket == null) {
            return false;
        }

        if (this.clientSocket.isClosed()) {
            return false;
        }

        try {

            this.out = new PrintWriter(
                    this.clientSocket.getOutputStream(), true);

            this.inputStream = new InputStreamReader(
                    this.clientSocket.getInputStream());

            this.in = new BufferedReader(this.inputStream);

            return true;

        } catch (IOException ex) {

            this.destroyClientMessageListener();
            ex.printStackTrace();

        }

        return false;
    }

    /**
     *
     */
    @Override
    public void run() {

        if (in != null) {

            String strInput;

            try {

                while ((strInput = this.in.readLine()) != null) {

                    final boolean success
                        = SRC.handleIncoming(
                            this.clientSocket, strInput);

                }

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

        }

    }

}

一切正常,当我在 destroy() 方法中关闭资源时,我希望 this.in.readLine() 调用抛出 IOException,因此线程刚刚结束。但是在调用 this.in.close() 时,destroy-method 会阻塞,并且绝对不会抛出异常。

即使 Thread.getCurrentThread.interrupt() 也不起作用,我不知道为什么。是否有一个干净的解决方案来关闭资源并结束 run() 方法?

【问题讨论】:

  • 为什么不直接关闭Socket
  • 很难说。你没有提供你的真实代码,只有“类似这样的东西”,所以谁知道。但是关闭Socket 肯定会毁掉你的听众。
  • 那里有很多不必要的代码。进行持续的空检查,就像您不知道您的对象处于什么状态一样。外部流/读取器也会关闭它们的内部流,因此您只需要关闭最外面的流。您可以用if(socket != null) { socket.close(); socket = null; } 替换整个destroy() 方法。
  • 不,它们不相关。你刚刚写了很多无意义的安全代码,因为你不明白什么会出错。至少您可以免受永远不会发生的情况的影响,但这只会导致大量不必要的代码。此外,如果资源没有正确初始化,你甚至不应该调用destroy()
  • 您还应该避免使用booleans 来指示方法成功。让异常冒泡并在初始化完成的地方处理它们。

标签: java multithreading sockets server client


【解决方案1】:

关闭套接字以进行输入。这将导致readLine() 返回null,这将导致正在读取套接字的线程将其关闭并退出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 2013-11-27
    • 1970-01-01
    • 2012-01-02
    • 2013-10-23
    相关资源
    最近更新 更多