我正在使用这种代码进行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到该缓冲区的所有内容?
此致
答案 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
没有内部缓冲区。您只需要阻塞一个读取循环即可。