Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 奈蒂:如何确定文件是否已完全发送?_Java_Netty_File Transfer - Fatal编程技术网

Java 奈蒂:如何确定文件是否已完全发送?

Java 奈蒂:如何确定文件是否已完全发送?,java,netty,file-transfer,Java,Netty,File Transfer,我正在尝试将文件(pdf/bpm/jpg/png)从java服务器应用程序发送到java客户端应用程序。 文件分块发送。但是我怎么知道文件何时被完全发送 我的第一个想法是使用channelReadComplete在文件已完全发送时获得通知。但是,由于它也是在文件仍在发送时触发的,因此它是无用的。对如何进行有什么建议吗 客户端管道: ChannelPipeline p = ch.pipeline(); p.addLast( "FileChunkHandler", new FileChunkHand

我正在尝试将文件(pdf/bpm/jpg/png)从java服务器应用程序发送到java客户端应用程序。 文件分块发送。但是我怎么知道文件何时被完全发送

我的第一个想法是使用
channelReadComplete
在文件已完全发送时获得通知。但是,由于它也是在文件仍在发送时触发的,因此它是无用的。对如何进行有什么建议吗

客户端管道:

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());
服务器管道:

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();
    }
}
公共类FileChunkHandler扩展了SimpleChannelInboundHandler{
私有ObjectOutputStream oout=null;
@重写受保护的无效channelRead0(ChannelHandlerContext ctx,ChunkedFile msg)引发异常{
System.out.println(“channelRead0”);
if(oout==null){
FileOutputStream out=新的FileOutputStream(“/Users/user/Documents/tmp/test/bla.txt”);
oout=新对象输出流(out);
}
ByteBuf buf=(ByteBuf)味精;
int numberOfReadableBytes=buf.readableBytes();
字节[]字节=新字节[numberOfReadableBytes];
buf.readBytes(字节);
oout.write(字节,0,字节.长度);
}
@重写公共无效channelReadComplete(ChannelHandlerContext ctx)引发异常{
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();
}
@覆盖公共无效channelRegistered(ChannelHandlerContext ctx)引发异常{
File File=新文件(“/Users/user/Documents/tmp/test/test.txt”);
RandomAccessFile raf=新的RandomAccessFile(文件“r”);
ChannelFuture sendFileFuture=null;
if(ctx.pipeline().get(SslHandler.class)==null){
sendFileFuture=ctx.write(新的DefaultFileRegion(raf.getChannel(),0,raf.length()),ctx.newProgressivePromise());
ctx.flush();
}否则{
sendFileFuture=ctx.writeAndFlush(文件,ctx.newProgressivePromise());
}
sendFileFuture.addListener(新通道ProgressiveFutureListener(){
@凌驾
公共无效运营进展(渠道进展未来、长期进展、长期总计){
如果(总数<0){//总数未知
System.err.println(future.channel()+“传输进度:”+进度);
}否则{
System.err.println(future.channel()+“传输进度:”+progress+“/”+total);
}
}
@凌驾
公共无效操作完成(渠道进展未来){
System.err.println(future.channel()+“传输完成”);
}
});
ctx.fireChannelRegistered();
}

使客户端和服务器通过套接字通信。当客户端向服务器发送文件时,服务器应向客户端发送“文件接收消息”

谷歌“用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);
}
}
公共类FileStatusHandler扩展了SimpleChannelInboundHandler{
@重写受保护的无效channelRead0(ChannelHandlerContext ctx,FileInformationModel msg)引发异常{
String name=“out”+msg.getName();
long length=msg.getLength();
FileDecoder FileDecoder=新的FileDecoder(长度、名称);
ctx.pipeline().addFirst(CommonClientDefines.Handler.FILE_DECODER,fileDecoder);
ctx.writeAndFlush(CommonClientDefines.READY\u FOR\u内容);
}
}
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);
    }
}
}
公共类FileDecoder扩展MessageToMessageDecoder{
私有最终字符串名;
私人最终长;
专用文件通道文件通道;
专用长接收长度=0;
公共文件解码器(长,字符串名)引发IOException{
这个长度=长度;
this.name=名称;
Path directoryPath=Path.get(System.getProperty(“user.home”)、“下载”、“tmp”、“测试”);
Path filePath=directoryPath.resolve(名称);
fileChannel=fileChannel.open(filePath,StandardOpenOption.CREATE,StandardOpenOption.WRITE);
}
@覆盖受保护的无效解码(ChannelHandlerContext ctx、ByteBuf msg、List out)引发异常{
receivedLength+=msg.readableBytes();
write(msg.nioBuffer());
如果(接收长度>=长度){
fileChannel.close();
ctx.pipeline().remove(CommonClientDefines.Handler.FILE\u解码器);
}
}
}

由于这种方法需要对我们的代码进行大量重构,所以这不是一个选项……他正在使用套接字。