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

Posted

技术标签:

【中文标题】套接字,BufferedReader 在 readLine() 处挂起【英文标题】:Socket, BufferedReader hangs at readLine() 【发布时间】:2011-08-24 16:24:15 【问题描述】:

我有一台服务器,它最初是这样做的:-

BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
for (;;) 
  String cmdLine = br.readLine();
  if (cmdLine == null || cmdLine.length() == 0)
     break; 
  ...

稍后它将套接字传递给另一个类“foo” 此类等待特定于应用程序的消息。

 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
 appCmd=br.readLine();

我的客户发送这个序列:

“栏\n” “你好吗?\n” “\n” “将其传递给 foo\n” “\n”

问题是有时“foo”没有得到响应。它挂在readLine()

服务器中的readLine() 使用预读缓冲数据并且“foo”类变得饥饿的可能性有多大?

如果我在客户端添加睡眠,它可以工作。但它始终有效的可能性有多大?

“栏\n” “你好吗?\n” “\n” sleep(1000); “将其传递给 foo\n” “\n”

如何解决问题?感谢您在这方面的任何帮助。

【问题讨论】:

您还可以在尝试读取数据之前使用 BufferedReader 的ready() 来检查数据是否准备就绪。在循环中执行此操作 如何解决问题? ready() - tell whether this stream is ready to be read。通常,我将它与read() 一起使用。我不将它与readLine() 一起使用,例如:while(true) if (br.ready()) br.read(cb); cb.flip(); String msg = cb.toString(); if (msg == null) break; cb 是具有一定缓冲区大小的CharBuffer。这种技术将允许读取缓冲区中允许的行数。 更多...***.com/questions/5244839/… 【参考方案1】:

答案可能晚了,但这是2020年最简单最新的答案,只需使用输入流read()方法从套接字服务器或客户端接收数据的简单方法即可。

EOFException会在客户端断开或服务器关闭连接时抛出。

private String waitForData() throws IOException 
    String data = "";
    do 
        int c = inputStream.read();
        if (c > -1) data += (char) c;
        else throw new EOFException();
     while (inputStream.available() > 0);
    return data;

【讨论】:

但是 inputStream.available() 有时会返回 0 并且当发送者发送消息并挂起 read() 消息时......【参考方案2】:

我遇到了同样的问题,这是我的解决方案:

try 
    StringBuilder response = new StringBuilder();
    response.append("SERVER -> CLIENT message:").append(CRLF);
    //Infinite loop
    while (true) 
        //Checks wheather the stream is ready
        if (in.ready()) 
            //Actually read line 
            lastLineFromServer = in.readLine();
            //If we have normal behavior at the end of stream
            if (lastLineFromServer != null) 
                response
                        .append(lastLineFromServer)
                        .append(CRLF);
             else 
                return response.toString();
            
         else //If stream is not ready
            //If number of tries is not exceeded
            if (numberOfTry < MAX_NUMBER_OF_TRIES) 
                numberOfTry++;
                //Wait for stream to become ready
                Thread.sleep(MAX_DELAY_BEFORE_NEXT_TRY);
             else //If number of tries is exeeded
                //Adds warning that things go weired
                response
                        .append("WARNING \r\n")
                        .append("Server sends responses not poroperly.\r\n")
                        .append("Response might be incomplete.")
                        .append(CRLF);
                return response.toString();
            
        
    
 catch (Exception ex) 
    ex.printStackTrace();
    return "";

【讨论】:

【参考方案3】:

eee 的解决方案完美运行。我试图从 SMTP 对话中读取输出,但它会阻塞:

while ((response = br.readLine()) != null) 
    ...Do Stuff

改为:

while (br.ready()) 
    response = br.readLine();
    ...Do Stuff

我可以很好地阅读所有内容。 br 是一个 BufferedReader 对象,顺便说一句。

【讨论】:

这是对我有用的解决方案。 readLine() 无缘无故卡住了,而 .ready() 完美地为我工作 在 ready() 之后使用 readLine() 时通常要小心。 Ready() 告诉你有数据要读取,但不代表就是一整行。所以 readLine() 仍然可以阻塞。 在我的情况下 br.ready() 在第一种情况下总是错误的【参考方案4】:

第一个 BufferedReader 中已经有数据(已从套接字读取,并且不再可从套接字获得),因此将第一个示例中创建的 BufferedReader 传递给读取应用程序的类特定消息,而不是从套接字创建一个新的BufferedReader

【讨论】:

我做不到。服务器不在我的控制之下。 foo 类在我的控制之下。为什么 BufferedReader 应该提前读取?我们不能控制吗? BufferedReader 不应该提前读取(通过查询)但不清空套接字。请注意,第一个“\n”确保服务器无法读取。 确实如此,但您无法更改;这就是它的 read 方法的约定:docs.oracle.com/javase/1.5.0/docs/api/java/io/…, int, int)

以上是关于套接字,BufferedReader 在 readLine() 处挂起的主要内容,如果未能解决你的问题,请参考以下文章

关闭 BufferedReader/PrintWriter 是不是会关闭套接字连接?

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

BufferedReader 上的 Java 客户端套接字阻塞?

java中关于bufferedreader类中read方法

套接字:将无符号字符数组从 C 传递到 JAVA

bufferedreaderreadline换行符不完全卡死