【问题标题】:BufferedReader readLine() blocksBufferedReader readLine() 块
【发布时间】: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循环?

标签: java sockets bufferedreader


【解决方案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();

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-01-08
          • 2015-06-07
          • 2021-04-15
          • 1970-01-01
          • 1970-01-01
          • 2015-09-29
          • 2013-12-16
          • 2018-09-26
          相关资源
          最近更新 更多