0

我在本地码头下运行客户端和 servlet。当我在客户端阅读消息时,我会:

in = new Scanner(conn.getInputStream());
StringBuffer messageBuffer = new StringBuffer();
while (in.hasNext()) {
   messageBuffer.append(in.next()).append(" ");
}

我希望当没有来自 servlet 的数据时,它应该冻结在

while (in.hasNext())

相反,我最终得到的是空的 messageBuffer,我必须处理它并一次又一次地调用该方法,直到我收到一条消息。为什么会这样?如何让它在 while 语句处停止并等到有数据进入?

以下是 url 连接的启动方式(一次,在客户端构造函数中):

try {
        url = new URL("http://localhost:8182/stream");
        conn = (HttpURLConnection) url.openConnection();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException ioE) {
        ioE.printStackTrace();
    }
4

4 回答 4

1

来自扫描仪文档:

next() 和 hasNext() 方法及其原始类型的伴随方法(例如 nextInt() 和 hasNextInt())首先跳过与分隔符模式匹配的任何输入,然后尝试返回下一个标记。hasNext 和 next 方法都可能阻塞等待进一步的输入。hasNext 方法是否阻塞与其关联的 next 方法是否会阻塞没有关系。

它说它可能会阻塞,但它不是api的一部分,它取决于您扫描的下划线实现。

无论如何,您需要通过以下方式自己实现等待:

while (!in.hasNext() && !stop){
   sleep();
}
于 2012-08-18T20:38:27.323 回答
1

javadoc 说明了这一点Scanner.hasNext()并且Scanner.next() 可能会阻塞。这真的取决于底层InputStream。如果是这样的话,我个人永远不会使用 aScanner从套接字读取。

InputStreamReader一种更理智的方法可能是使用由 a 包裹的 an BufferedReader。另外值得一提的是你应该使用StringBuilder而不是StringBuffer除非你需要线程安全。

BufferedReader br = 
    new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String input = null;
while ((input = br.readLine()) != null)
{
    sb.append(input).append(" ");
}

请注意readLine(),这可能会或可能不适合您的需求,具体取决于您收到的内容。它还假设连接的另一端在发送完成后将关闭。您可能希望改用其中一种read()方法并相应地进行解析。

编辑从下面的评论中添加:这实际上是阻塞读取在 Java 中的工作方式。这是一个完整的例子:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class App 
{
    public static void main( String[] args ) throws MalformedURLException, IOException
    {
        URL url = new URL("http://www.google.com");

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        BufferedReader br = 
            new BufferedReader(new InputStreamReader(conn.getInputStream()));
        StringBuilder sb = new StringBuilder();
        String input = null;
        while ((input = br.readLine()) != null)
        {
            sb.append(input).append(" ");
        }

        System.out.println(sb.toString());

    }
}

输出(此处为简洁起见,但它是整个页面):

<!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage"><head> ...
于 2012-08-18T20:46:45.793 回答
0

编辑:

尝试使用 for 循环而不是 while 循环,其中范围将从 0 到(长度 -1)。您必须使用 while(in.hasNextLine()) 查找长度并将长度计数器放入其中。完成填充 messageBuffer(使用 .close())后,不要忘记关闭扫描仪。试试看。它应该工作。

于 2012-08-18T20:35:23.900 回答
0

根据我的经验,我一直试图避免阻塞,因此避免对 hasNext() 使用 Scanner 方法。

相反,我使用了 InputStream。InputStream,您在代码中使用过:

conn.getInputStream();

然后,您可以使用 InputStream 方法available()来查看是否有任何信息通过。

因此,对于您的代码,我建议:

InputStream inStream = conn.getInputStream();
in = new Scanner(inStream);    
StringBuffer messageBuffer = new StringBuffer();    
while (in.available() <= 0)
{   
 try{
    Thread.sleep(100);
}
catch(InterruptedException e){}
}
messageBuffer.append(in.next()).append(" ");
于 2012-08-18T22:50:25.777 回答