BufferedReader 从未准备好(Java 中的 Socket 编程)

发布于 2024-11-09 02:25:18 字数 1251 浏览 5 评论 0原文

我已经像这样声明了套接字:

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

但是,以下内容不起作用。 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();
        }

    }

我该如何解决这个问题?

编辑:

这就是我的服务器类中的发送方式: 输出.println(消息); 出.flush(); 每当我在消息中放入某些内容时,就会循环发生这种情况。 out 在这个循环之后被关闭。

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();

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.flush();
This happens in a loop whenever i've put something in message. out is closed after this loop.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

岁月苍老的讽刺 2024-11-16 02:25:18

您不应该像这样使用 ready()javadoc 说这:

“返回:如果保证下一次 read() 不会阻塞输入,则返回 True,否则返回 false。请注意,返回 false 并不能保证下一次读取会阻塞。”

您的代码隐式假设 ready() -> ; false 表示下一个读取将被阻塞。事实上,这意味着下一个读取可能会或可能不会阻塞。

正如 @EJP 所说...只需执行 read 调用即可。


我可以做些什么来防止阻塞?如果被阻止,客户端将无法发送任何内容

如果读取阻塞对您的应用程序来说是一个问题,请使用单独的线程来执行读取,或者更改代码以使用 NIO 通道选择器。

You shouldn't be using ready() like this. The javadoc says this:

"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. "

Your code is implicitly assuming that ready() -> false means that the next read will block. In actual fact, it means the next read might or might not block.

As @EJP says ... just do the read call.


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.

看轻我的陪伴 2024-11-16 02:25:18

只需删除 in.ready() 测试即可。这对你没有帮助。 readLine() 将阻塞,直到有数据可用。如果还没有数据到达,您还打算做什么?

Just remove the in.ready() test. It isn't helping you. readLine() will block until there is data available. What else were you planning to do if no data has arrived yet?

花伊自在美 2024-11-16 02:25:18

我想到了三件事:

  • 您在每个 receive 调用中重新打开输入流,并将其包装到 BufferedReader 中。这可能会在缓冲区中读取不止一行,并且在完成(关闭它)后,剩余的缓冲字节将不再可用于后续的 receive 调用
  • 您是否考虑过使用自己的线程进行读取服务器消息?如果它被阻塞也不会造成伤害
  • 我在写入数据后关闭套接字的一侧并立即关闭它时遇到了一些问题。有时,尽管调用了 flush()close(),但另一方并未收到所有数据。也许这也是您遇到的问题

编辑:
简单地将 in 引用保留在 receive 方法之外并不能完全解决您的问题。您应该使用 while 循环来读取所有缓冲的消息并为每个人调用侦听器,例如:

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

但请注意最后一行可能是部分读取的消息(例如 3 和 1/2 消息被缓冲)。如果这是一个问题,您可以逐个字符地读取消息以确定行何时结束,并使用 PushbackReader 放回不完整的消息。

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. 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
  • 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. 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. You should use a while loop for reading all buffered messages and call the listener for everyone, e.g.:

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

But watch out as the last line might be a partially read message (e.g. 3 and 1/2 messages were buffered). 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.

旧时浪漫 2024-11-16 02:25:18

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

You may need to call out.flush() to flush anything in BufferedWriter

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文