2015-10-06 249 views
0

我試圖從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(); 
} 

回答

0

讓您的客戶端和服務器通過套接字comunicate。當客戶端向服務器發送文件時,服務器應向客戶端發送「文件已接收消息」。

Google「用Java發送套接字消息」中,有很多示例。

希望它有幫助。

+0

由於這種方法需要大量重構我們的代碼,所以這不是一個選項... – KayJ

0

我解決了這個問題(但我還沒完全滿意)。歡迎進一步的反饋!

我正在創建一個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); 
    } 
} 
}