Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/395.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:正确的网络IO处理?_Java_Network Programming_Io - Fatal编程技术网

Java:正确的网络IO处理?

Java:正确的网络IO处理?,java,network-programming,io,Java,Network Programming,Io,我遇到的问题是,当我使用InputStream读取字节时,它会阻塞,直到连接完成。例如: InputStream is = socket.getInputStream(); byte[] buffer = new byte[20000]; while (is.read(buffer) != -1) { System.out.println("reading"); } System.out.pr

我遇到的问题是,当我使用InputStream读取字节时,它会阻塞,直到连接完成。例如:

        InputStream is = socket.getInputStream();
        byte[] buffer = new byte[20000];
        while (is.read(buffer) != -1) {
            System.out.println("reading");
        }
        System.out.println("socket read");
在实际收到FYN数据包之前,“套接字读取”不会打印出来,从而关闭连接。在不阻塞和等待连接断开的情况下,接收所有字节的正确方法是什么?

看看哪种方法有支持。

示例取自


一定要理解缓冲区翻转,因为它会引起很多头痛。基本上,您必须反转缓冲区才能从中读取。如果要重用该缓冲区以使套接字写入,则必须再次翻转它。然而clear()会重置缓冲区方向。

对于传统套接字,关键是通常您确实希望它们阻塞:当您在逻辑上不希望程序阻塞时,您所做的是将您的读/写代码放在另一个线程中,以便单独的读/写线程阻塞,而不是整个程序

否则,可以使用available()方法在读取之前查看是否有任何可用的输入。但是,您需要小心,不要坐在循环中不断调用available()来消耗CPU

编辑:如果问题是在字节到达之前,而不是在连接断开之前(这就是发生的情况),您很乐意阻塞,那么您需要让另一端的客户端在发送字节后对其输出流进行flush()。

读取直到获得-1表示您希望读取到EOS。如果你不想在EOS之前阅读,不要循环到-1:更快停止。问题是‘什么时候?’

如果您只想阅读完整的“消息”,则必须以读者可以找到其结尾的方式发送消息:例如,类型长度值协议,或者更简单地说,每条消息前的大小字,或者自描述协议,如XML。请尝试以下方法:

        InputStream is = socket.getInputStream();
        byte[] buffer = new byte[20000];
        int bytesRead;
        do {
            System.out.println("reading");
            bytesRead = is.read(buffer);
        }
        while (is.available() > 0 && bytesRead != -1);
        System.out.println("socket read");

更多信息:

代码可能没有按照您认为的那样执行。 read(buffer)返回它读取的字节数,换句话说:填充缓冲区并不是保证。 有关填充整个数组的代码,请参见DataInputStream.readFully()

或者您可以使用以下函数(基于DataInputStream.readFully()):


跟进:有没有一种方法可以阻止这种情况?我想在它连接之前阻止,但使用while(!sChannel.finishedConnect())会占用大量的cpu周期。选择OP_CONNECT并在获得它时选中finishConnect(),否则只需在阻止模式下连接。是的,请更正最后一点烧坏cpu的情况。有没有一种观点化的方法不会影响cpu周期或上下文切换(Thread.sleep(long)+轮询是否会导致性能损失?调用Thread.sleep()会导致实际I/O的性能损失(例如,您可以睡眠500毫秒,但100毫秒后数据就准备好了,而您需要400毫秒才能收到数据).在上下文切换方面,每秒多几个C/S并不重要。但我仍然不清楚:为什么不能让套接字阻塞(如果需要,在它自己的线程中)?对不起,我确实希望它阻止第一次循环,读取字节,我的问题是我对java IO不熟悉,因为我再次调用read,然后我不得不等待EOS。当你发现它不总是有效时,请重新查看我的答案。对
is.available()
的调用不应该发生在
is.read()之前吗
调用,考虑到
是.read()
如果第一次读取时没有可用的字节,可能会阻塞?我确实希望它阻塞,直到第一次读取时有可用的字节。我发现这是最优化的,因为它不消耗CPU资源,也不轮询。此外,这段代码对我来说运行得很好,今天早上测试过。如果我遇到问题,我会更新。这听起来像是个问题乔在这一点上做得太过火了。我认为他应该先掌握阻塞io,然后再考虑非阻塞io。
        InputStream is = socket.getInputStream();
        byte[] buffer = new byte[20000];
        int bytesRead;
        do {
            System.out.println("reading");
            bytesRead = is.read(buffer);
        }
        while (is.available() > 0 && bytesRead != -1);
        System.out.println("socket read");
public final void readFully(InputStream in, byte b[]) throws IOException
{
    readFully(in, b, 0, b.length);
}

public final void readFully(InputStream in, byte b[], int off, int len) throws IOException
{
    if (len < 0) throw new IndexOutOfBoundsException();
    int n = 0;
    while (n < len)
    {
        int count = in.read(b, off + n, len - n);
        if (count < 0) throw new EOFException();
        n += count;
    }
}
InputStream is = socket.getInputStream();
byte[] buffer = new byte[20000];
readFully(is, buffer);
System.out.println("socket read");