【问题标题】:java.io.BufferedReader.readLine() is nonblockingjava.io.BufferedReader.readLine() 是非阻塞的
【发布时间】:2013-05-06 13:18:58
【问题描述】:

我在 Java 中遇到了 readLine() 的问题。我有一个服务器和一个客户端。从客户端我想向服务器发送消息。问题是,首先,客户端必须将文本插入到 JTextField 中,当按下发送时,服务器从客户端读取输入,但服务器不等待来自客户端的输入,而是读取 null。但是我读到 readLine() 被阻止,直到它有要读的东西,为什么在这种情况下没有发生?

这里我连接到服务器并创建 JFrame

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class StartingPoint {

private static PrintWriter out;
private static BufferedReader in;

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                connectToServer();
                createAndShowGui();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });
}

public static void createAndShowGui() throws IOException {
    View frame = new View(out, in);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setLocationByPlatform(true);
    frame.setVisible(true);
}

public static void connectToServer() throws IOException {
    String serverAddress = "127.0.0.1";

    int PORT = 8100;

    Socket clientSocket = null;
    out = null;
    in = null;

    try {
        clientSocket = new Socket(serverAddress, PORT);
        out = new PrintWriter(clientSocket.getOutputStream(), true);
        in = new BufferedReader(new InputStreamReader(
                clientSocket.getInputStream()));
    } catch (UnknownHostException e) {
        System.err.println("Could not connect to the server \n" + e);
        System.exit(1);
    } finally {
        if (out != null)
            out.close();
        if (in != null)
            in.close();
        if (clientSocket != null)
            clientSocket.close();
    }
}
}

这里是 JFrame 的实现:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class View extends JFrame {

private JButton button;
private JTextField field;
private JPanel gui;

public View(final PrintWriter out, final BufferedReader in) throws IOException {

    button = new JButton("Send");
    field = new JTextField();

    gui = new JPanel(new GridLayout(1, 0, 10, 10));

    gui.add(button);
    gui.add(field);

    add(gui);

    button.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            out.println(field.getText());

            try {
                System.out.println(in.readLine());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}
}

这里是服务器:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class SimpleServer extends Thread {

public static final int PORT = 8100;
private static ServerSocket serverSocket = null;

private Socket clientSocket = null;

public void run() {
    String receive, answer;
    try {
        BufferedReader in = new BufferedReader(new InputStreamReader(
                clientSocket.getInputStream()));

        PrintWriter out = new PrintWriter(clientSocket.getOutputStream());

        receive = in.readLine();
        System.out.println("[server]" +  receive);
        answer = "hello " + receive;
        out.println(answer);
        out.flush();

    } catch (IOException e) {
        System.err.println("IO error \n" + e);
    } finally {
        try {
            clientSocket.close();
        } catch (IOException e) {
            System.err.println("Close socket error \n" + e);
        }

    }
}

public SimpleServer() throws IOException {

    while (true) {
        serverSocket = new ServerSocket(PORT);
        try {
            clientSocket = serverSocket.accept();

            new Thread(this).start();

        } finally {
            serverSocket.close();
        }
    }
}

public static void main(String[] args) throws IOException {
    SimpleServer server = new SimpleServer();
}
}

【问题讨论】:

    标签: java swing sockets nonblocking readline


    【解决方案1】:

    您的 connectToServer() 方法打开一个连接,创建流,然后......然后在返回之前关闭它们。所以当然,服务器会立即看到关闭,并在第一次 readLine() 调用时返回 null


    我怀疑您可能在不理解它的含义的情况下复制了“在 finally 块中关闭”模式。所以我来解释一下:

    这是正常模式:

    InputStream is = null;
    try {
        is = new FileInputStream(someFile);
        // read the stream
    } finally {
        if (is != null) {
            is.close();
        }
    }
    

    上述代码的目的是确保 InputStream 始终处于关闭状态。或者更准确地说,它总是在try/finally 退出之前关闭

    这通常是一件好事。但是,如果您的代码的目的是打开一些将在这段代码完成后使用的流,那么在这里关闭流就是自取灭亡。

    InputStream is = null;
    try {
        is = new FileInputStream(someFile);
    } finally {
        if (is != null) {
            is.close();
        }
    }
    // read the stream ... OOOPS!  We've already closed it!!
    

    因此,要将其恢复为您的原始代码,您需要将 try/finally/close 内容移至 run 方法,类似于以下内容:

        public void run() {
            try {
                connectToServer();
                createAndShowGui();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (out != null)
                    out.close();
                if (in != null)
                    in.close();
                if (clientSocket != null)
                    clientSocket.close();
            } 
        }
    

    您还应该捕获并(可能)忽略每个 close() 调用可能引发的 IOException

    【讨论】:

      【解决方案2】:

      BufferedReader.readLine() 的 Javadoc 没有这样说:

      返回: 包含行内容的String,不包括 任何行终止字符,如果已到达流的末尾,则为 null

      在您的代码中,您在 connectToServer() 中打开一个连接并关闭它,因此服务器会看到流的结尾

      【讨论】:

        猜你喜欢
        • 2012-11-13
        • 2014-10-19
        • 1970-01-01
        • 2011-12-30
        • 1970-01-01
        • 1970-01-01
        • 2016-07-06
        • 1970-01-01
        • 2023-03-19
        相关资源
        最近更新 更多