我正在进行一个项目,以更好地了解Java NIO和网络编程内容。我正在尝试通过netcat将400,000字节以上的文件发送到我的服务器,该文件将在其中找到并写入文件。
问题:当文件小于10,000字节时,或者当我在Select()之前放置Thread.sleep(timeout)时,该程序都能完美运行。该文件发送过来,但仅读取8192字节,然后从循环中取消并返回到select()以捕获其余数据。但是,该文件将捕获之后的内容。我需要完整的数据以进一步扩展到该项目。
我尝试过的事情:我试图将数据加载到另一个显然有效的字节数组上,但是跳过了8192个字节(因为select()被再次调用)。读取其余的391000字节。比较文件时,前8192个字节丢失。我已经尝试了其他各种方法,但是我在NIO中还不足以理解自己的想法。
我的代码
这就是我觉得代码混乱的地方(调试后)
private void startServer() {
File temp = new File("Filepath");
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(listenAddress);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
log.info("Server Socket Channel Started");
while(!stopRequested){
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
for(SelectionKey key : keys){
if(key.isAcceptable()){
try {
serverSocketChannel = (ServerSocketChannel) key.channel();
SocketChannel socket = serverSocketChannel.accept();
socket.configureBlocking(false);
socket.register(selector, SelectionKey.OP_READ);
}catch (IOException e) {
log.error("IOException caught: ", e);
}
}
if(key.isReadable(){ read(key); }
keys.remove(key);
}
}
} catch (IOException e) {
log.error("Error: ", e);
}
}
private void read(SelectionKey key) {
int count = 0;
File tmp = new File("Path");
try {
SocketChannel channel = (SocketChannel) key.channel();
byteBuffer.clear();
while((count = channel.read(byteBuffer)) > 0) {
byteBuffer.flip();
//in bytearrayoutputstream to append to data byte array
byteArrayOutputStream.write(byteBuffer.array(), byteBuffer.arrayOffset(), count);
byteBuffer.compact();
}
}
data = byteArrayOutputStream.toByteArray();
FileUtils.writeByteArrayToFile(tmp, data);
}
}
上面的代码是我正在使用的代码。我在该课程中有更多东西,但我相信遇到问题的主要两个功能是这两个。我不太确定应该采取什么步骤。我必须测试程序的文件包含许多约400,000字节的TCP。 select()收集最初的8192字节,然后运行read(在它捕获流中的所有数据之前不应该发生),然后返回并收集其余部分。我已将byteBuffer分配为30720字节。
如果不清楚,我可以发布其余代码,让我知道您的建议。
问题当分配的空间为30720时,为什么此代码仅捕获8192个字节?为什么它在调试模式下或与Thread.sleep()一起工作?
以前的人建议我将我的byteBuffer.clear()放在循环外,即使这样做,问题仍然存在。
我强烈建议您首先重新考虑是否需要非阻塞(它总是几乎慢得多,并且开发难度要大几个数量级。毕竟,您不能在任何处理程序代码或应用中的任何地方进行单个可能阻塞的调用在负载下将变得缓慢,并且Java在等待/屈服方面不是很出色–唯一的真正好处是您可以对缓冲区大小进行更细粒度的控制,除非您受到非常有限的RAM约束并且可以使用较小的缓冲区,否则这是无关紧要的每个连接状态)。然后,如果您得出结论,确实这是唯一的方法,请使用使该API易于使用的库,例如netty。