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

时间:2010-04-01 11:50:30

标签: 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字节的数据包到达,则din.available()无论如何都会返回2048。就像有一个2048内部缓冲区。当我知道它不是我的应用程序正在等待的完整数据包时,我无法读取那些2048字节。如果我不读它 - 它将全部停留在2048字节并且永远不会收到更多。

我可以以某种方式扩大DataInputStream的缓冲区大小吗?套接字接收缓冲区是sock.getReceiveBufferSize()返回的16384,因此不是套接字将我限制为2048字节。

如果无法增加DataInputStream缓冲区大小 - 我想唯一的方法是声明我自己的缓冲区并读取从DataInputStream到该缓冲区的所有内容?

此致

5 个答案:

答案 0 :(得分:2)

我将假设你所谓的“数据包”。我将假设您的“数据包”是传递给您的服务器的一些工作单元。以太网TCP数据包限制为1536字节。无论对等端执行什么大小的写操作。

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

鉴于此,一种方法是让一个线程对din进行阻塞读取。只需处理数据,直到您拥有完整的数据包。然后将数据包传递给另一个线程来处理数据包本身。 (见ArrayBlockingQueue。)

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

答案 1 :(得分:1)

将数据输入流包裹在较大的缓冲输入流中:

DataInputStream din =
  new DataInputStream(
    new BufferedInputStream( sock.getInputStream( ), 4096 )
  );

但我认为它不会对你有所帮助。您必须使用套接字中的输入,否则发送方将卡住。

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

答案 2 :(得分:0)

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

另请注意,InputStream的API状态

  

请注意,虽然有些实现   InputStream将返回总数   流中的字节数,很多   将不会。它永远不会正确使用   此方法的返回值为   分配一个旨在容纳所有人的缓冲区   此流中的数据。

因此,仅仅因为您收到的值为2048并不意味着没有更多可用数据,它只是保证无阻塞地读取的数量。另请注意,虽然Alexander建议的BufferedInputStream是一个选项,但它不能保证缓冲区将始终被填充(事实上,如果你查看源它只会在其中一个读取调用时尝试填充缓冲区)。

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

不能。 DataInputStream没有内部缓冲区。您只需要阻塞一个读取循环即可。