Java 中的 OutputStream 是否阻塞?(插座)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10574596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is an OutputStream in Java blocking? (Sockets)
提问by salbeira
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. 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.
在考虑之后我现在的问题是天气与否 Java Socket 的 OutputStream 实际上将他想要发送的东西自己排队,从而预先消除了对队列的需要。只有当服务器阻塞时,只要他没有从客户端收到发送对象已收到的响应,就会出现严重问题的可能性。
Thanks.
谢谢。
采纳答案by eppesuig
Of course, when you write to a socket, this write is buffered. Socket object have a setSendBufferSize()
method for setting this buffer size. 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.
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.
当然,当您写入套接字时,此写入会被缓冲。Socket 对象有一个setSendBufferSize()
设置这个缓冲区大小的方法。如果您的写入可以缓存在此缓冲区中,那么您当然可以立即在以下套接字上进行迭代。否则这个缓冲区需要立即刷新到客户端。因此,在冲洗期间,您将被阻塞。如果您想避免在刷新缓冲区时被阻塞,则必须使用SocketChannel
in 非阻塞 I/O。无论如何,并发写入多个套接字的最佳选择是使用不同的线程管理每个套接字,以便所有写入可以同时执行。
回答by Tomasz Nurkiewicz
Your friend is right but it has more to do with how tcpipprotocol 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. In turns this avoid the requirement to resend big amounts of data.
你的朋友是对的,但这更多地与tcpip协议的工作方式有关。需要确认发送到客户端的大大简化的数据包。如果客户端没有响应(无法读取传入数据、计算机负载过重等),服务器将不会收到确认并停止发送数据。TCP/IP 中内置的这种机制可以防止通信的一端发送大量数据,而不能确保另一端收到它们。反过来,这避免了重新发送大量数据的要求。
In Java this manifests as blocking write to OutputStream
. The underlying TCP/IP stack/operating system does not allow sending more data until the client is ready to receive it.
在 Java 中,这表现为阻塞写入OutputStream
. 在客户端准备好接收数据之前,底层 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). However if I read from inputStream
in server thread - the loop goes on and on.
客户端循环在 95 次迭代后挂在我的电脑上(你的里程可能会有所不同)。但是,如果我从inputStream
服务器线程中读取- 循环继续进行。
回答by Keith Randall
An OutputStream is blocking. 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.
OutputStream 正在阻塞。它可能有一些缓冲,但是如果服务器从不消耗字节(任何固定的缓冲区最终都会填满),那对您没有多大帮助。所以你的朋友是对的,你需要在单独的线程中编写,或者使用更高级的东西,例如nio。
On the reading side, you can use available() to avoid blocking. No matching call exists on the write side. I wish there was.
在阅读方面,您可以使用 available() 来避免阻塞。写入端不存在匹配的调用。我希望有。