简体   繁体   English

BufferedReader从未准备好(用Java编写Socket编程)

[英]BufferedReader never ready (Socket programming in Java)

I have socket already declared socket like this: 我有套接字已经声明套接字像这样:

serverAddr = InetAddress.getByName(this.ip);
socket = new Socket(serverAddr, port);
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);

however, the following doesn't work. 但是,以下不起作用。 in.ready() always returns false and if removed the program will freeze at String message = in.readLine(); in.ready()总是返回false,如果删除,程序将冻结在String message = in.readLine();

private void receive() {
        try {
            InputStreamReader isr = new InputStreamReader(socket.getInputStream());
            System.out.println(isr.getEncoding());
            BufferedReader in = new BufferedReader(isr);
            if (in.ready()) {
                String message = in.readLine();
                if (message != null) {
                    if (listener != null) {
                        listener.receiveMessage(ip, message);
                    } else {
                        print("Client recieved: " + message);//
                    }
                }
            }
            in.close();
        } catch (Exception e) {
            print("Error with input stream: " + e);
            disconnect();
        }

    }

How could i solve this? 我怎么能解决这个问题?

EDIT: 编辑:

This is how sending looks like in my server class: out.println(message); 这就是我的服务器类中的发送方式:out.println(message); out.flush(); 了out.flush(); This happens in a loop whenever i've put something in message. 每当我在消息中放入某些内容时,就会发生这种情况。 out is closed after this loop. 在此循环后关闭。

You shouldn't be using ready() like this. 你不应该像这样使用ready() The javadoc says this: javadoc说:

"Returns: True if the next read() is guaranteed not to block for input, false otherwise. Note that returning false does not guarantee that the next read will block. " “返回:如果保证下一个read()不阻止输入,则返回true,否则返回false。注意,返回false并不能保证下一次读取将阻塞。”

Your code is implicitly assuming that ready() -> false means that the next read will block. 您的代码隐式假设ready() -> false表示下一次read将阻塞。 In actual fact, it means the next read might or might not block. 实际上,这意味着下一次read 可能会阻止也可能不会阻塞。

As @EJP says ... just do the read call. 正如@EJP所说......只是做read通话。


What could i do to prevent a block though? 我该怎么做才能防止阻塞呢? The client will be unable to send anything if it's blocked 如果被阻止,客户端将无法发送任何内容

If blocking in read is a problem for your application, either use a separate thread to do the reading, or change your code to use NIO channel selectors. 如果读取中的阻塞是应用程序的问题,请使用单独的线程进行读取,或者更改代码以使用NIO通道选择器。

Just remove the in.ready() test. 只需删除in.ready()测试即可。 It isn't helping you. 它没有帮助你。 readLine() will block until there is data available. readLine()将阻塞,直到有可用数据。 What else were you planning to do if no data has arrived yet? 如果还没有数据到达,你还打算做什么?

There are 3 things that come to my mind: 我想到了三件事:

  • You are re-opening the input stream in every receive call, and wrapping it into a BufferedReader . 您将在每个receive调用中重新打开输入流,并将其包装到BufferedReader This might read more than a single line into the buffer, and after finishing (closing it), the remaining buffered bytes will no longer be available for subsequent receive calls 这可能会在缓冲区中读取多行,并且在完成(关闭它)之后,剩余的缓冲字节将不再可用于后续的receive调用
  • Did you think about using an own thread for reading the server messages? 您是否考虑过使用自己的线程来读取服务器消息? There it won't harm if it is blocked 如果它被阻止,它不会受到伤害
  • I have experienced some problems when closing one side of a socket after writing data, and immediately closing it. 在写入数据后关闭套接字的一侧并立即关闭它时,我遇到了一些问题。 Sometimes not all of the data was received by the other side, despite flush() and close() calls. 尽管有flush()close()调用,但有时并不是所有数据都被另一方接收。 Maybe this is also an issue in your situation 也许在你的情况下这也是一个问题

Edit: 编辑:
Smiply keeping the in reference outside of the receive method will not fully solve your problem. Smiply保持in该外部参考receive方法不能完全解决你的问题。 You should use a while loop for reading all buffered messages and call the listener for everyone, eg: 您应该使用while循环来读取所有缓冲的消息并为每个人调用侦听器,例如:

if (in.ready()) {
    String message;
    while ((message = in.readLine()) != null) {
        // ...
    }
 }

But watch out as the last line might be a partially read message (eg 3 and 1/2 messages were buffered). 但请注意,最后一行可能是部分读取的消息(例如,3和1/2消息被缓冲)。 If this is an issue, you could read the messages char-by-char for determining when a line ends, and use a PushbackReader for putting back incomplete messages. 如果这是一个问题,您可以读取消息char-by-char以确定行何时结束,并使用PushbackReader来放回不完整的消息。

您可能需要调用out.flush()来刷新BufferedWriter任何内容

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM