如何在不阻塞的情况下从Java中读取BufferedReader?

时间:2012-06-30 11:41:25

标签: java stream blocking bufferedreader inputstreamreader

我想将命令发送到服务器,并查明我是否收到回复。

现在我正在使用BufferedReader的{​​{1}}函数,它阻止服务器响应,但我想做的就是首先验证服务器是否有响应

我尝试使用readline()ready()来避免此阻止,但它无济于事。

这导致我的程序卡住等待服务器响应,这种情况从未发生过。 reset()似乎也是根据我对事物的理解做同样的事情。

我在这个问题上找到的其他问题没有回答我的问题, 所以,如果你能回答我的问题,那就太好了。

4 个答案:

答案 0 :(得分:3)

如果你想异步读取响应,我建议启动一个读取BufferedReader的线程。这对代码来说更简单,更容易控制。

答案 1 :(得分:1)

可能只需要InputStream而不是将其包含在BufferedReader

while (inputStream.available() > 0) {
     int i = inputStream.read(tmp, 0, 1024);
     if (i < 0)
          break;
     strBuff.append(new String(tmp, 0, i));
}

我希望这会有所帮助。

答案 2 :(得分:0)

我最近使用CountDownLatch做了类似的事情。可能有一些更好的方法,但这很容易,而且似乎工作得相当好。您可以调整CountDownLatch的等待时间以满足您的需要。

package com.whatever;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestRead {
    private static final Logger log = LoggerFactory.getLogger(TestRead.class);
    private CountDownLatch latch = new CountDownLatch(1);

    public void read() {
        URLReader urlReader = new URLReader();
        Thread listener = new Thread(urlReader);
        listener.setDaemon(true);
        listener.start();
        boolean success = false;
        try {
            success = latch.await(20000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            log.error("error", e);
        }
        log.info("success: {}", success);
    }

    class URLReader implements Runnable {
        public void run() {
            log.info("run...");
            try {
                URL oracle = new URL("http://www.oracle.com/");
                URLConnection yc = oracle.openConnection();
                BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
                String inputLine;
                while ((inputLine = in.readLine()) != null)
                    System.out.println(inputLine);
                in.close();
                latch.countDown();
            } catch (Exception ex) {
                log.error("error", ex);
            }
            log.info("consumer is done");
        }

    }
    public static void main(String[] args) {
        TestRead testRead = new TestRead();
        testRead.read();
    }
}

答案 3 :(得分:0)

如果使用标准的Java IO,这是一项棘手的任务,不会被阻塞。常见的答案是迁移到NIO或Netty。网购是更可取的选择。但是有时候您别无选择,所以我建议您尝试一下解决方法:

public String readResponse(InputStream inStreamFromServer, int timeout) throws Exception {
    BufferedReader reader = new BufferedReader(new InputStreamReader(inStreamFromServer, Charsets.UTF_8));
    char[] buffer = new char[8092];
    boolean timeoutNotExceeded;
    StringBuilder result = new StringBuilder();
    final long startTime = System.nanoTime();
    while ((timeoutNotExceeded = (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) < timeout))) {
        if (reader.ready()) {
            int charsRead = reader.read(buffer);
            if (charsRead == -1) {
                break;
            }
            result.append(buffer, 0, charsRead);
        } else {
            try {
                Thread.sleep(timeout / 200);
            } catch (InterruptedException ex) {
                LOG.error("InterruptedException ex=", ex);
            }
        }
    }
    if (!timeoutNotExceeded) throw new SocketTimeoutException("Command timeout limit was exceeded: " + timeout);

    return result.toString();
}

此解决方法不是灵丹妙药,但它具有一些重要功能:

  • 不使用readline()。此方法对于网络通信很危险,因为某些服务器不会返回LF/CR符号,并且您的代码将被卡住。当您从文件中读取内容时,这并不重要,无论如何您都将到达文件结尾。
  • 不使用char symbol = (char) fr.read();。这种方法比读取char []
  • 它具有超时功能,您可能会在连接速度较慢时中断通信