简体   繁体   English

Java中的OutputStream是阻塞的吗? (插座)

[英]Is an OutputStream in Java blocking? (Sockets)

I am currently writing naive network code for a project and a mate hinted me at the possibility that when I send a package of information from the server to all clients in an iterative fashion I might get intense lag when one of the clients is not responding properly. 我目前正在为一个项目编写天真的网络代码,并且一位伙伴暗示我有可能当我以一种迭代的方式从服务器向所有客户端发送信息包时,当其中一个客户端没有正确响应时,我可能会遇到严重的延迟。

He is reknown for trolling so I was kind of sceptical when implementing a secondary thread that is now responsible to send data over to a client, having a queue that the Server simply adds the packages over that is then read by the thread to send data. 他因拖钓而闻名,所以当我实现一个现在负责将数据发送到客户端的辅助线程时,我有点怀疑,它有一个队列,服务器只是简单地添加了包,然后被线程读取以发送数据。

The question I now have after thinking it over is weather or not the OutputStream of a Java Socket actually queues the stuff he wants to send by itself, thus eliminating the need of a queue beforehand. 在考虑它之后我现在遇到的问题是天气与否,Java Socket的OutputStream实际上将他想要发送的东西排队,因此事先不需要队列。 The possibility of having intense problems occurrs only when the Server is blocking as long as he does not get a response from a client that the sent object was recieved. 只有当客户端没有收到来自客户端的已收到发送对象的响应时,才会出现发生严重问题的可能性。

Thanks. 谢谢。

Your friend is right but it has more to do with how protocol works. 你的朋友是对的,但它更多地与协议的工作方式有关。 Largely simplifying packets sent to the client need to be confirmed. 需要确认大大简化发送到客户端的数据包。 If the client is not responding (fails to read incoming data, computer is under heavy load, etc.) the server won't receive acknowledgements and will stop sending the data. 如果客户端没有响应(无法读取传入数据,计算机负载过重等),服务器将不会收到确认并将停止发送数据。 This mechanism built into TCP/IP prevents one end of the communication from sending large amounts of data without making sure the other end received them. 内置于TCP / IP中的这种机制可防止通信的一端发送大量数据,而不会确保另一端收到它们。 In turns this avoid the requirement to resend big amounts of data. 反过来,这避免了重新发送大量数据的要求。

In Java this manifests as blocking write to OutputStream . 在Java中,这表示阻止写入OutputStream The underlying TCP/IP stack/operating system does not allow sending more data until the client is ready to receive it. 底层TCP / IP堆栈/操作系统不允许在客户端准备好接收数据之前发送更多数据。

You can easily test this! 你可以轻松测试这个! I implemented simple server that accepts connection but fails to read incoming data: 我实现了接受连接但无法读取传入数据的简单服务器:

new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            final ServerSocket serverSocket = new ServerSocket(4444);
            final Socket clientSocket = serverSocket.accept();
            final InputStream inputStream = clientSocket.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}).start();

And a simple client that just sends as much data as it can in 4K batches: 还有一个简单的客户端,可以在4K批次中发送尽可能多的数据:

final Socket client = new Socket("localhost", 4444);
final OutputStream outputStream = client.getOutputStream();
int packet = 0;
while(true) {
    System.out.println(++packet);
    outputStream.write(new byte[1024 * 4]);
}

The client loop hangs on my computer after 95 iterations (your mileage may vary). 95次迭代后,客户端循环在我的计算机上挂起(您的里程可能会有所不同)。 However if I read from inputStream in server thread - the loop goes on and on. 但是,如果我从服务器线程中的inputStream读取 - 循环继续。

Of course, when you write to a socket, this write is buffered. 当然,当您写入套接字时,此写入将被缓冲。 Socket object have a setSendBufferSize() method for setting this buffer size. Socket对象有一个setSendBufferSize()方法来设置此缓冲区大小。 If your write can be cached in this buffer, then of course, you may iterate immediately on the following socket. 如果您的写入可以缓存在此缓冲区中,那么您当然可以立即在以下套接字上进行迭代。 Otherwise this buffer need to be flushed to the client immediately. 否则,需要立即将此缓冲区刷新到客户端。 So, during flushing you are going to be blocked. 因此,在冲洗期间,您将被阻止。 If you want to avoid being blocked while flushing the buffer, you have to use a SocketChannel in non blocking I/O. 如果要在刷新缓冲区时避免被阻塞,则必须在非阻塞I / O中使用SocketChannel Anyway, the best option for writing to many socket concurrently, is to manage each socket with a different thread, so that all writes may be executed at the same time. 无论如何,同时写入多个套接字的最佳选择是使用不同的线程管理每个套接字,以便可以同时执行所有写入。

An OutputStream is blocking. OutputStream正在阻塞。 It probably has some buffering, but that doesn't help you much if the server is never consuming bytes (any fixed buffer will eventually fill up). 它可能有一些缓冲,但如果服务器从不消耗字节(任何固定缓冲区最终将填满),这对你没有多大帮助。 So your friend is right, you need to write in a separate thread, or use something more advanced, like nio. 所以你的朋友是对的,你需要在一个单独的线程中写,或者使用更高级的东西,比如nio。

On the reading side, you can use available() to avoid blocking. 在阅读方面,您可以使用available()来避免阻塞。 No matching call exists on the write side. 写入端不存在匹配的调用。 I wish there was. 我希望有。

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

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