简体   繁体   English

从Socket使用InputStream时,Scanner.nextLine()会阻塞

[英]Scanner.nextLine() blocks when using InputStream from Socket

When I receive data using Socket.getInputStream() directly (without some kind of interface like Scanner), it doesn't block. 当我直接使用Socket.getInputStream()接收数据时(没有像Scanner这样的某种接口),它不会阻塞。 But, when I try to use a Scanner (similar to how we receive Strings from System.in ), it does. 但是,当我尝试使用扫描仪时(类似于我们从System.in接收字符串的方式),它确实如此。 I was wondering the reason for this, and how the InputStream that a connected Socket supplies to you is different from the InputStream in in System . 我想知道这个的原因,以及连接的Socket提供给你的InputStream inSystemInputStream in有什么不同。

The Client used for testing (used for both servers) 用于测试的客户端(用于两个服务器)

The code that hangs: 挂起的代码:

public class Server {

    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(15180);
            Socket socket = ss.accept();

            Scanner scanner = new Scanner(socket.getInputStream());
            //read data from client
            while(true) {
                String data = scanner.nextLine();
                System.out.println("Received data!");
            }

        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

The code that doesn't block: 不阻止的代码:

public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(15180);
            Socket socket = ss.accept();

            //read data from client
            while(true) {
                int data = socket.getInputStream().read();
                System.out.println("Received data!");
            }

        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

(I think you've already figured this out but ...) (我想你已经想到了这个但是...)

The readLine() method returns the rest of the current line. readLine()方法返回当前行的其余部分。 That is, all unconsumed characters up to the next "end of line" sequence, or the "end of stream", which ever comes first. 也就是说,所有未消耗的字符直到下一个“行尾”序列,或者“流的结束”,它始终是第一个。 It will block, waiting until the current line (according to the above) is available. 它将阻塞,等待当前行(根据上述)可用。

So if your socket readLine() call blocks, it is waiting for the remote to either send an end-of-line marker (eg '\\n' ), or close its socket output stream (which will result in an "end-of-stream" at this end). 因此,如果您的套接字readLine()调用块,它正在等待远程发送行尾标记(例如'\\n' ),或关闭其套接字输出流(这将导致“结束” - “在这一端”。

Q: Why does it "work" when you read from the console? 问:当你从控制台读取时,为什么它“起作用”?

A: The console adds an "end-of-line" sequence to the stream whenever you hit ENTER. 答:无论何时按Enter键,控制台都会向流添加“行尾”序列。 (Precisely what sequence is added is OS dependent, but the Scanner class will cope with all common varieties, and some unusual ones too.) (确切地说,添加的序列是依赖于操作系统的,但Scanner类将处理所有常见的变种,以及一些不寻常的变种。)


The lesson here is that you should only use Scanner.readLine() if the input stream is line oriented; 这里的教训是,如果输入流是面向行的,你应该只使用Scanner.readLine() ; ie if whatever wrote / generated the stream is including "end-of-line" markers. 即如果写入/生成的流包括“行尾”标记。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM