BufferedReader readLine() 块

Posted

技术标签:

【中文标题】BufferedReader readLine() 块【英文标题】:BufferedReader readLine() blocks 【发布时间】:2013-03-09 10:01:43 【问题描述】:

当使用 readLine() 接收数据时,即使我在消息末尾放了一个“\n” 发送消息时使用 .flush ,读取我的消息的while循环仍然阻塞。 只有在关闭套接字连接时,才会离开循环。

这是客户端代码:

bos = new BufferedOutputStream(socket.
            getOutputStream());
bis = new BufferedInputStream(socket.
            getInputStream());
osw = new OutputStreamWriter(bos, "UTF-8");
osw.write(REG_CMD + "\n");
osw.flush();

isr = new InputStreamReader(bis, "UTF-8");
BufferedReader br = new BufferedReader(isr);

String response = "";
String line;

while((line = br.readLine()) != null)
   response += line;

和服务器的代码:

BufferedInputStream is;
BufferedOutputStream os;

is = new BufferedInputStream(connection.getInputStream());
os = new BufferedOutputStream(connection.getOutputStream());

isr = new InputStreamReader(is);

String query= "";
String line;

while((line = br.readLine()) != null)
   query+= line;


String response = executeMyQuery(query);
osw = new OutputStreamWriter(os, "UTF-8");

osw.write(returnCode + "\n");
osw.flush();

我的代码在服务器 while 循环中阻塞。 谢谢。

【问题讨论】:

将代码放入 try/catch 块中,并在 finally 块中关闭流/连接。 这似乎没有问题。您想知道为什么会发生这种行为吗?如何预防? 如果你只想读一行为什么要使用while循环? 【参考方案1】:

BufferedReader 将继续读取输入,直到它到达末尾(文件或流或源等的结尾)。在这种情况下,“结束”是套接字的关闭。因此,只要 Socket 连接打开,您的循环就会运行,而 BufferedReader 只会等待更多输入,每次到达 '\n' 时都会循环。

【讨论】:

嗯我不认为结束是套接字的关闭。谢谢。现在我看它,我误读了文档! 当涉及到非文件流的 eof 时,该文档相当模糊。 是 OP 的循环一直读取到 EOS,而不是 BufferedReader。 所以如果连接打开但缓冲区中没有行,它还会循环吗? @the_prole - 循环将继续......有点。它不会退出循环,但 br.readLine() 调用将阻塞,直到有新行可用【参考方案2】:

我尝试了很多解决方案,但唯一没有阻止执行的是:

BufferedReader inStream = new BufferedReader(new InputStreamReader(yourInputStream));
String line;
while(inStream.ready() && (line = inStream.readLine()) != null) 
    System.out.println(line);

如果下一个 readLine() 调用将阻止执行,则 inStream.ready() 返回 false。

【讨论】:

你救了我一个月。我只需要反转 inStream.ready()(line = inStream.readLine()) != null 我的 InputStream 是从 java.lang.Process 获得的 @LennoardSilva 是的,我的也是从java.lang.Process 获得的,所以你不会知道什么时候没有什么可以用其他方法阅读了。【参考方案3】:

这是因为while循环中的条件:while((line = br.readLine()) != null)

您在每次迭代时读取一行,如果 readLine 返回null,则退出循环。

如果达到 eof(= socked 已关闭),readLine 仅返回 null,如果读取了 '\n',则返回一个字符串。

如果你想在 readLine 上退出循环,你可以省略整个 while 循环,直接做:

line = br.readLine()

【讨论】:

【参考方案4】:

发生这种情况是因为 InputStream 还没有准备好变红,所以它在 in.readLine() 上阻塞。 请试试这个:

boolean exitCondition= false;

while(!exitCondition)
    if(in.ready())
        if((line=in.readLine())!=null)
            // do whatever you like with the line
        
    

当然你要控制exitCondition。

另一个选项可以是使用 nio 包,它允许异步(非阻塞)读取,但这取决于您的需要。

【讨论】:

【参考方案5】:

最好避免使用readline()。这种方法对网络通信很危险,因为有些服务器不返回LF/CR 符号,你的代码就会卡住。当您从文件中读取时,这并不重要,因为无论如何您都会到达文件末尾并且流将被关闭。

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

它有一个超时,如果需要很长时间你可以中断通信

【讨论】:

您必须确定您使用的协议。大多数协议都指定了它们的行尾行为。【参考方案6】:

如果您想在不强制关闭它的情况下获取套接字中的内容,只需使用 ObjectInputStream 和 ObjectOutputStream ..

示例:

ObjectInputStream ois;
ObjectOutputStream oos;

ois = new ObjectInputStream(connection.getInputStream());

String dataIn = ois.readUTF(); //or dataIn = (String)ois.readObject();

oos = new ObjectOutputStream(connection.getOutputStream());
oos.writeUtf("some message"); //or use oos.writeObject("some message");
oos.flush();

.....

【讨论】:

【参考方案7】:

readline() 和 read() 将在套接字未关闭时被阻塞。所以你应该关闭套接字:

Socket.shutdownInput();//after reader
Socket.shutdownOutput();//after wirite

而不是 Socket.close();

【讨论】:

以上是关于BufferedReader readLine() 块的主要内容,如果未能解决你的问题,请参考以下文章

为啥 BufferedReader read() 比 readLine() 慢得多?

套接字,BufferedReader 在 readLine() 处挂起

在 while 循环中正确使用 BufferedReader.readLine()

BufferedReader readLine() 块

Java:BufferedReader 的 readLine 方法的效率和可能的替代方案

正确地在while循环中使用BufferedReader.readLine()