Java 如何修复从netty服务器下载的不完整内容
我正在实现一些简单的netty服务器和客户端来发送和修改文件。类似于云存储的东西 我有一个服务器,它处理传入的请求并将文件发送回客户端。我还希望我的应用程序能够处理大文件,这就是为什么我将这些文件分成块并逐块发送。但有一个问题我无法解决 比如说:Java 如何修复从netty服务器下载的不完整内容,java,netty,Java,Netty,我正在实现一些简单的netty服务器和客户端来发送和修改文件。类似于云存储的东西 我有一个服务器,它处理传入的请求并将文件发送回客户端。我还希望我的应用程序能够处理大文件,这就是为什么我将这些文件分成块并逐块发送。但有一个问题我无法解决 比如说: 我们在服务器上有一个4 gb文件 它被分成4万块 然后它们被发送到客户端应用程序,我可以看到服务器上的所有区块都被写入套接字,因为我使用int字段作为消息编号(区块编号),并将正在写入的消息编号放入日志 但是,当客户机接收到消息(块)时,对于大文件
- 我们在服务器上有一个
文件4 gb
- 它被分成4万块
- 然后它们被发送到客户端应用程序,我可以看到服务器上的所有区块都被写入套接字,因为我使用int字段作为消息编号(区块编号),并将正在写入的消息编号放入日志
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29055
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29056
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29057
客户端开始接收连续消息-1、2、3、4。。。27878、27879
,然后毫无例外地停止,尽管来自服务器的最后一条消息是,例如40000
差点忘了说我在客户端应用程序中使用了JavaFX
因此,我尝试使用xms xmx java vm选项,但没有任何帮助
服务器
public class Server {
public void run() throws Exception {
EventLoopGroup mainGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(mainGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(
new ObjectDecoder(Constants.FRAME_SIZE, ClassResolvers.cacheDisabled(null)),
new ObjectEncoder(),
new MainHandler()
);
}
})
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture future = b.bind(8189).sync();
future.channel().closeFuture().sync();
} finally {
mainGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new Server().run();
}
}
分块发送文件的方法
private void sendFileToClient(ChannelHandlerContext ctx, String fileName) throws IOException {
Path path = Paths.get("server_storage/" + fileName);
if (Files.exists(path)) {
if (Files.size(path) > Constants.FRAME_SIZE) {
sendServerDataFrames(ctx, path);
ctx.writeAndFlush(new FileRequest(FileCommand.LIST_FILES));
} else {
FileMessage fm = new FileMessage(path);
ctx.writeAndFlush(fm);
}
}
}
private void sendServerDataFrames(ChannelHandlerContext ctx, Path path) throws IOException {
byte[] byteBuf = new byte[Constants.FRAME_CHUNK_SIZE];
FileMessage fileMessage = new FileMessage(path, byteBuf, 1);
FileRequest fileRequest = new FileRequest(FileCommand.SEND_PARTIAL_DATA, fileMessage);
FileInputStream fis = new FileInputStream(path.toFile());
int read;
while ((read = fis.read(byteBuf)) > 0) {
if (read < Constants.FRAME_CHUNK_SIZE) {
byteBuf = Arrays.copyOf(byteBuf, read);
fileMessage.setData(byteBuf);
}
ctx.writeAndFlush(fileRequest);
fileMessage.setMessageNumber(fileMessage.getMessageNumber() + 1);
}
System.out.println("server_storage/" + path.getFileName() + ", server last frame number: " + fileMessage.getMessageNumber());
System.out.println("server_storage/" + path.getFileName() + ": closing file stream.");
fis.close();
}
这就是我在服务器上看到的
server_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 42151
server_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 42152
server_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso, server last frame number: 42153
server_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: closing file stream.
这是一个客户机
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29055
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29056
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29057
从客户端向服务器发送文件时没有问题。我可以在调试器和windows任务管理器中看到这两个进程同时工作,但当文件从服务器发送到客户端时,情况并非如此。首先读取所有数据块,然后将其发送给客户端,客户端开始接收这些数据块,但无法获取所有数据块。请帮忙。我不知道会是什么。提前感谢。请确保在未来的
writeAndFlush
中捕获异常,它们可能包含您问题的线索,请参阅如何阅读这些异常的示例谢谢。找到原因真的很有帮助。很明显,netty无法释放messge从服务器获取的内存,因为message类未实现ReferenceCounted接口。解决此问题的另一种方法是将a与a结合使用,因此只有在网络层处理了Yes的第一部分可能重复时,才发送文件的下一部分,与其再发明一个字节码,不如使用已经实现的功能。请确保在未来的writeAndFlush
中捕获异常,它们可能包含问题的线索,请参阅如何读取这些异常的示例谢谢。找到原因真的很有帮助。很明显,netty无法释放messge从服务器获取的内存,因为message类未实现ReferenceCounted接口。解决此问题的另一种方法是将a与a结合使用,因此只有在网络层处理了Yes的第一部分可能重复时,才发送文件的下一部分,最好使用已经实现的功能,而不是再发明一个字节。
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29055
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29056
client_storage/DVD5_OFFICE_2010_SE_SP2_VOLUME_X86_RU-KROKOZ.iso: 29057