Java 如何更改DataInputStream的内部缓冲区大小

Java 如何更改DataInputStream的内部缓冲区大小,java,android,sockets,network-programming,Java,Android,Sockets,Network Programming,我在TCP/IP连接中使用这种代码: sock = new Socket(host, port); sock.setKeepAlive(true); din = new DataInputStream(sock.getInputStream()); dout = new DataOutputStream(sock.getOutputStream()); 然后,在单独的线程中,我检查din.available()字节,看看是否有一些传入的数据包需要读取 问题是,如果一个大于2048字节的数据包到

我在TCP/IP连接中使用这种代码:

sock = new Socket(host, port);
sock.setKeepAlive(true);
din = new DataInputStream(sock.getInputStream());
dout = new DataOutputStream(sock.getOutputStream());
然后,在单独的线程中,我检查
din.available()
字节,看看是否有一些传入的数据包需要读取

问题是,如果一个大于2048字节的数据包到达,
din.available()
仍然返回2048字节。就像有一个2048年的内部缓冲区一样。当我知道应用程序等待的不是完整的数据包时,我无法读取2048字节。但是,如果我不读它,它将停留在2048字节,永远不会收到更多

我能否以某种方式扩大
DataInputStream
的缓冲区大小?Socket接收缓冲区是由sock.getReceiveBufferSize()返回的16384,因此它不是限制我使用2048字节的套接字

如果没有办法增加
DataInputStream
缓冲区大小,我想唯一的办法就是声明我自己的缓冲区并读取从DataInputStream到该缓冲区的所有内容


关于

围绕较大的缓冲输入流包装数据输入流:

DataInputStream din =
  new DataInputStream(
    new BufferedInputStream( sock.getInputStream( ), 4096 )
  );
但我不认为这对你有帮助。您必须使用来自套接字的输入,否则发送方将被卡住


您可能应该花更多的时间制定更好的通信协议。

将数据输入流围绕较大的缓冲输入流:

DataInputStream din =
  new DataInputStream(
    new BufferedInputStream( sock.getInputStream( ), 4096 )
  );
但我不认为这对你有帮助。您必须使用来自套接字的输入,否则发送方将被卡住


您可能应该花更多的时间制定更好的通信协议。

如果深入研究DataInputStream的源代码,getAvailable()实际上被委托给读取它的流,因此2048来自套接字输入流,而不是DataInputStream(默认情况下在本机代码中实现)

还请注意,InputStream的API状态为

注意,虽然有些实现 的InputStream将返回总数 流中的字节数,多个 不会。使用它是不正确的 此方法的返回值为 分配一个缓冲区,用于保存所有 此流中的数据

因此,仅仅因为您收到2048的值并不意味着没有更多的可用数据,这只是保证在不阻塞的情况下读取的数据量。还要注意的是,虽然正如Alexander所建议的BufferedInputStream是一个选项,但它并不保证总是填充缓冲区(事实上,如果查看源代码,它只会在进行一个读取调用时尝试填充缓冲区)


因此,如果您想确保始终收到“完整数据包”,您最好创建自己的输入流包装器,在其中可以添加特殊方法“byte[]readPacket()”当从底层套接字流读取数据时,它将阻塞直到可以填充自己的缓冲区。

如果深入研究DataInputStream的源,getAvailable()实际上被委托给它读取的流,因此2048来自套接字输入流,而不是DataInputStream(默认情况下在本机代码中实现)

还请注意,InputStream的API状态为

注意,虽然有些实现 的InputStream将返回总数 流中的字节数,多个 不会。使用它是不正确的 此方法的返回值为 分配一个缓冲区,用于保存所有 此流中的数据

因此,仅仅因为您收到2048的值并不意味着没有更多的可用数据,这只是保证在不阻塞的情况下读取的数据量。还要注意的是,虽然正如Alexander所建议的BufferedInputStream是一个选项,但它并不保证总是填充缓冲区(事实上,如果查看源代码,它只会在进行一个读取调用时尝试填充缓冲区)


因此,如果您想确保始终收到“完整数据包”,您最好创建自己的输入流包装器,在其中可以添加一个特殊方法“byte[]readPacket()”,该方法将阻塞,直到在从底层套接字流读取数据时它可以填充自己的缓冲区。

这不是使用InputStreams的方式。你永远不想使用可用的方法,它几乎是无用的。如果需要读取数据的“数据包”,则需要将其设计到协议中。一种简单的方法是先发送数据包的长度,然后再发送数据包。接收器读取数据包的长度,然后从数据流中准确读取那么多字节。

这不是使用InputStreams的方式。你永远不想使用可用的方法,它几乎是无用的。如果需要读取数据的“数据包”,则需要将其设计到协议中。一种简单的方法是先发送数据包的长度,然后再发送数据包。接收器读取数据包的长度,然后从数据流中准确地读取那么多字节。

我将假设您称之为“数据包”。我将假设您的“数据包”是传递给服务器的某个工作单元。以太网TCP数据包限制为1536字节。无论对等方执行的写入大小如何

因此,您不能期望每次都以原子方式阅读完整的工作单元。这不会发生的。你写的东西需要确定它有多大。这可以通过预先传递一个值来完成,该值告诉服务器应该期望多少数据

鉴于此,一种方法是让线程在
din
上执行阻塞读取。只要处理数据,直到你有一个完整的数据包。然后将数据包传递给另一个线程以处理数据包本身。(见附件。)


套接字读取器线程将以数据到达的任何速率和粒度处理数据。数据包处理器线程总是以完整数据包的形式工作。

我将假设您所称的“数据包”是什么。