Netty:如何确定文件是否已完整发送?
问题描述:
我试图从java服务器应用程序发送文件(pdf/bpm/jpg/png)到java客户端应用程序。 该文件以块形式发送。但是,如何知道文件何时完全发送?Netty:如何确定文件是否已完整发送?
我的第一个想法是使用得到通知,如果文件已完全发送。但是由于它在文件仍在发送时也被触发,所以它是无用的。有关如何进行的任何建议?
客户端管道:
ChannelPipeline p = ch.pipeline();
p.addLast("FileChunkHandler", new FileChunkHandler());
服务器管道:
p.addLast("Encoder", new ObjectEncoder());
p.addLast("Decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
p.addLast("chunkedWriteHandler", new ChunkedWriteHandler());
p.addLast("FileSenderHandler", new FileSenderHandler());
的FileChunkHandler在客户端:
public class FileChunkHandler extends SimpleChannelInboundHandler<ChunkedFile>{
private ObjectOutputStream oout = null;
@Override protected void channelRead0(ChannelHandlerContext ctx, ChunkedFile msg) throws Exception{
System.out.println("channelRead0");
if (oout == null){
FileOutputStream out = new FileOutputStream("/Users/user/Documents/tmp/test/bla.txt");
oout = new ObjectOutputStream(out);
}
ByteBuf buf = (ByteBuf)msg;
int numberOfReadableBytes = buf.readableBytes();
byte[] bytes = new byte[numberOfReadableBytes];
buf.readBytes(bytes);
oout.write(bytes, 0, bytes.length);
}
@Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception{
System.out.println("channelReadComplete");
ctx.fireChannelReadComplete();
}
}
的FileSenderHandler在服务器上:
公共类FileSenderHandler扩展ChannelInboundHandlerAdapter {
@Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception{
File file = new File("/Users/user/Documents/tmp/test/test.txt");
RandomAccessFile raf = new RandomAccessFile(file, "r");
ChannelFuture sendFileFuture = null;
if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, raf.length()), ctx.newProgressivePromise());
ctx.flush();
} else {
sendFileFuture = ctx.writeAndFlush(file, ctx.newProgressivePromise());
}
sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
@Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
if (total < 0) { // total unknown
System.err.println(future.channel() + " Transfer progress: " + progress);
} else {
System.err.println(future.channel() + " Transfer progress: " + progress + "/" + total);
}
}
@Override
public void operationComplete(ChannelProgressiveFuture future) {
System.err.println(future.channel() + " Transfer complete.");
}
});
ctx.fireChannelRegistered();
}
答
让您的客户端和服务器通过套接字comunicate。当客户端向服务器发送文件时,服务器应向客户端发送“文件已接收消息”。
Google“用Java发送套接字消息”中,有很多示例。
希望它有帮助。
答
我解决了这个问题(但我还没完全满意)。欢迎进一步的反馈!
我正在创建一个FileStatusHandler,它接收一个包含文件信息(如长度和名称)的模型。这些信息作为参数传递给FileDecoder,该FileDecoder被添加到管道中。
public class FileStatusHandler extends SimpleChannelInboundHandler<FileInformationModel>{
@Override protected void channelRead0(ChannelHandlerContext ctx, FileInformationModel msg) throws Exception{
String name = "out_" +msg.getName();
long length = msg.getLength();
FileDecoder fileDecoder = new FileDecoder(length, name);
ctx.pipeline().addFirst(CommonClientDefines.Handler.FILE_DECODER, fileDecoder);
ctx.writeAndFlush(CommonClientDefines.READY_FOR_CONTENT);
}
}
FileDecoder本身负责接收文件内容,并在收到文件时删除处理程序。
public class FileDecoder extends MessageToMessageDecoder<ByteBuf>{
private final String name;
private final long length;
private FileChannel fileChannel;
private long receivedLength = 0;
public FileDecoder(long length, String name) throws IOException{
this.length = length;
this.name = name;
Path directoryPath = Paths.get(System.getProperty("user.home"), "Download", "tmp", "test");
Path filePath = directoryPath.resolve(name);
fileChannel = FileChannel.open(filePath, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
}
@Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception{
receivedLength += msg.readableBytes();
fileChannel.write(msg.nioBuffer());
if(receivedLength >= length){
fileChannel.close();
ctx.pipeline().remove(CommonClientDefines.Handler.FILE_DECODER);
}
}
}
由于这种方法需要大量重构我们的代码,所以这不是一个选项... – KayJ