Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
输出流是Java阻塞吗?(插座)_Java_Sockets_Implementation_Blocking_Outputstream_Tcpip - Fatal编程技术网

输出流是Java阻塞吗?(插座)

输出流是Java阻塞吗?(插座),java,sockets,implementation,blocking,outputstream,tcpip,Java,Sockets,Implementation,Blocking,Outputstream,Tcpip,我目前正在为一个项目编写简单的网络代码,一位同事向我暗示,当我以迭代方式从服务器向所有客户端发送一个信息包时,当其中一个客户端没有正确响应时,可能会出现严重的延迟 他以拖拉而闻名,所以当实现一个现在负责向客户机发送数据的辅助线程时,我有点怀疑,因为它有一个队列,服务器只需在上面添加包,然后由线程读取以发送数据 仔细考虑后,我现在的问题是,Java套接字的OutputStream是否会将他想要发送的内容自动排队,从而消除了事先排队的需要。只有当服务器阻塞时,只要他没有从客户端收到接收到发送对象的响

我目前正在为一个项目编写简单的网络代码,一位同事向我暗示,当我以迭代方式从服务器向所有客户端发送一个信息包时,当其中一个客户端没有正确响应时,可能会出现严重的延迟

他以拖拉而闻名,所以当实现一个现在负责向客户机发送数据的辅助线程时,我有点怀疑,因为它有一个队列,服务器只需在上面添加包,然后由线程读取以发送数据

仔细考虑后,我现在的问题是,Java套接字的OutputStream是否会将他想要发送的内容自动排队,从而消除了事先排队的需要。只有当服务器阻塞时,只要他没有从客户端收到接收到发送对象的响应,才会出现严重问题


谢谢。

你的朋友是对的,但这与协议的工作方式有很大关系。发送到客户端的数据包需要确认,这在很大程度上简化了。如果客户端没有响应(无法读取传入数据,计算机负载过大等),服务器将不会收到确认,并将停止发送数据。这种内置于TCP/IP中的机制防止通信的一端发送大量数据,而不确保另一端接收到数据。这样就避免了重新发送大量数据的要求

在Java中,这表现为阻止写入
OutputStream
。在客户端准备接收数据之前,底层TCP/IP堆栈/操作系统不允许发送更多数据

你可以很容易地测试这个!我实现了一个简单的服务器,它接受连接但无法读取传入数据:

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();
还有一个简单的客户端,它可以在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]);
}

客户端循环在95次迭代后挂起在我的计算机上(您的里程数可能会有所不同)。但是,如果我在服务器线程中读取
inputStream
,则循环会不断进行。

一个OutputStream正在阻塞。它可能有一些缓冲,但如果服务器从不消耗字节(任何固定的缓冲区最终都会填满),这对您没有多大帮助。所以你的朋友是对的,你需要在一个单独的线程中编写,或者使用更高级的东西,比如nio


在读取端,可以使用available()来避免阻塞。写入端不存在匹配的调用。我希望有。

当然,当您写入套接字时,这种写入会被缓冲。套接字对象具有设置此缓冲区大小的方法。如果您的写操作可以缓存在这个缓冲区中,那么当然,您可以立即在下面的套接字上进行迭代。否则,需要立即将此缓冲区刷新到客户端。所以,在冲洗过程中,您将被阻塞。如果要避免在刷新缓冲区时被阻塞,必须在非阻塞I/O中使用
SocketChannel

无论如何,并发写入多个套接字的最佳选择是使用不同的线程管理每个套接字,以便可以同时执行所有写入操作。

“否则需要立即将此缓冲区刷新到客户端”不是正确的放置方式。缓冲区一直异步写入网络,但只有在对等方的接收缓冲区中有空间时才能发送。如果对等方没有读取,或者读取速度变慢,那么他的接收缓冲区将填满,因此您的发送缓冲区将填满,因此您后续的写入操作将被阻止。尽管Tomasz的文章是一个更好的示例,但这正是我在EJP中寻找的解释。非常感谢。如果我尝试在线程的run函数中获取输出或输入流,我会遇到类似的问题。套接字阻塞(getInputStream和getOutputStream)的问题是因为它在运行函数中。。。解决方案似乎是将其放入构造函数中,保存变量,然后在run中引用变量。如果我尝试在线程的run函数中获取输出或输入流,我会遇到类似的问题。套接字阻塞(getInputStream和getOutputStream)的问题是因为它在运行函数中。。。解决方案似乎是将其放入构造函数中,保存变量,然后在运行时引用变量。