无法使用netty发送大型zip文件

无法使用netty发送大型zip文件,netty,Netty,我想从客户机向服务器发送一个大的zip文件,然后从服务器向客户机发送一个收到该文件的回复。我正在使用io.netty.handler.stream.ChunkedWriteHandler发送大文件。我的问题是如何知道服务器何时接收到整个数据,因为在服务器端,读取数据的代码似乎无限期地运行。客户端和服务器端的代码如下: File file = new File("file1.zip"); ChunkedFile chunkedFile; try { chunkedFile = new C

我想从客户机向服务器发送一个大的zip文件,然后从服务器向客户机发送一个收到该文件的回复。我正在使用io.netty.handler.stream.ChunkedWriteHandler发送大文件。我的问题是如何知道服务器何时接收到整个数据,因为在服务器端,读取数据的代码似乎无限期地运行。客户端和服务器端的代码如下:

File file  = new File("file1.zip");
ChunkedFile chunkedFile;
try {
    chunkedFile = new ChunkedFile(file);
    client.send(chunkedFile);
} catch (IOException e) {
    e.printStackTrace();
}
import java.io.File;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.stream.ChunkedFile;
import io.netty.util.ReferenceCountUtil;

public class FileChunkReqWriteHandler extends SimpleChannelInboundHandler<ChunkedFile> {
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("in channel active method");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();

        if (ctx.channel().isActive()) {
            ctx.writeAndFlush("ERR: " +
                    cause.getClass().getSimpleName() + ": " +
                    cause.getMessage() + '\n').addListener(ChannelFutureListener.CLOSE);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ChunkedFile msg)
            throws Exception {
        System.out.println("in channelRead0");

    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);
    }

}
客户端代码为:

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.stream.ChunkedFile;
import io.netty.handler.stream.ChunkedWriteHandler;


public class Client {


    private Bootstrap bootstrap;

    private boolean connected;

    /**
     * Port number of the socket server.
     */
    private final int port;

    /**
     * Host name of the socket server.
     */
    private final String hostName;


    private NioEventLoopGroup nioEventLoopGroup;

    private ChannelFuture futureChannel;


    /**
     * Initialize the socket details
     * 
     */
    public Client(final String hostName, final int port) {
        this.hostName = hostName;
        this.port = port;
        connected = false;
    }

    /**
     * Connects to the host and port.
     * 
     * 
     */
    public void connect() throws GridException {

        this.bootstrap = new Bootstrap();
        nioEventLoopGroup = new NioEventLoopGroup();

        this.bootstrap.group(nioEventLoopGroup).channel(NioSocketChannel.class)
        .handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline p = ch.pipeline();
                p.addLast(new ChunkedWriteHandler());
            }
        });

        // Make the connection attempt.
        try {
            futureChannel = bootstrap.connect(hostName, port).sync();
            connected = true;       

        } catch (InterruptedException e) {

        }
    }

    public boolean isConnected() {
        return connected;
    }

    public void close() {
        futureChannel.channel().closeFuture();
        nioEventLoopGroup.shutdownGracefully();
    }


    public void send(final ChunkedFile file) {
        futureChannel.channel().writeAndFlush(file);
    }

}
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.stream.ChunkedWriteHandler;

public class Server {

    private EventLoopGroup eventLoopGroup;
    private EventLoopGroup slaveEventLoopGroup;
    private int packagePort;
    private ChannelHandler fileReqHandler;


    public void start() throws GridException {
        eventLoopGroup = new NioEventLoopGroup();
        slaveEventLoopGroup = new NioEventLoopGroup();
        ServerBootstrap server = null;

        server = new ServerBootstrap();
        server.group(eventLoopGroup, slaveEventLoopGroup)
        .channel(NioServerSocketChannel.class) // (3)
        .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new ChunkedWriteHandler());
                ch.pipeline().addLast(fileReqHandler);
            }
        })
        .option(ChannelOption.SO_BACKLOG, 128)          // (5)
        .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

        try {
            server.bind(getPackagePort()).sync();
        } catch (InterruptedException e) {
            throw new GridException(e);
        }        
    }

    @Override
    public void shutdown() throws GridException {
        eventLoopGroup.shutdownGracefully();
        slaveEventLoopGroup.shutdownGracefully();        
    }

    public int getPackagePort() {
        return packagePort;
    }

    public void setPackagePort(int packagePort) {
        this.packagePort = packagePort;
    }

    public ChannelHandler getFileReqHandler() {
        return fileReqHandler;
    }

    public void setFileReqHandler(ChannelHandler fileReqHandler) {
        this.fileReqHandler = fileReqHandler;
    }


}
服务器端代码为:

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.stream.ChunkedFile;
import io.netty.handler.stream.ChunkedWriteHandler;


public class Client {


    private Bootstrap bootstrap;

    private boolean connected;

    /**
     * Port number of the socket server.
     */
    private final int port;

    /**
     * Host name of the socket server.
     */
    private final String hostName;


    private NioEventLoopGroup nioEventLoopGroup;

    private ChannelFuture futureChannel;


    /**
     * Initialize the socket details
     * 
     */
    public Client(final String hostName, final int port) {
        this.hostName = hostName;
        this.port = port;
        connected = false;
    }

    /**
     * Connects to the host and port.
     * 
     * 
     */
    public void connect() throws GridException {

        this.bootstrap = new Bootstrap();
        nioEventLoopGroup = new NioEventLoopGroup();

        this.bootstrap.group(nioEventLoopGroup).channel(NioSocketChannel.class)
        .handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline p = ch.pipeline();
                p.addLast(new ChunkedWriteHandler());
            }
        });

        // Make the connection attempt.
        try {
            futureChannel = bootstrap.connect(hostName, port).sync();
            connected = true;       

        } catch (InterruptedException e) {

        }
    }

    public boolean isConnected() {
        return connected;
    }

    public void close() {
        futureChannel.channel().closeFuture();
        nioEventLoopGroup.shutdownGracefully();
    }


    public void send(final ChunkedFile file) {
        futureChannel.channel().writeAndFlush(file);
    }

}
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.stream.ChunkedWriteHandler;

public class Server {

    private EventLoopGroup eventLoopGroup;
    private EventLoopGroup slaveEventLoopGroup;
    private int packagePort;
    private ChannelHandler fileReqHandler;


    public void start() throws GridException {
        eventLoopGroup = new NioEventLoopGroup();
        slaveEventLoopGroup = new NioEventLoopGroup();
        ServerBootstrap server = null;

        server = new ServerBootstrap();
        server.group(eventLoopGroup, slaveEventLoopGroup)
        .channel(NioServerSocketChannel.class) // (3)
        .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
            @Override
            public void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new ChunkedWriteHandler());
                ch.pipeline().addLast(fileReqHandler);
            }
        })
        .option(ChannelOption.SO_BACKLOG, 128)          // (5)
        .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

        try {
            server.bind(getPackagePort()).sync();
        } catch (InterruptedException e) {
            throw new GridException(e);
        }        
    }

    @Override
    public void shutdown() throws GridException {
        eventLoopGroup.shutdownGracefully();
        slaveEventLoopGroup.shutdownGracefully();        
    }

    public int getPackagePort() {
        return packagePort;
    }

    public void setPackagePort(int packagePort) {
        this.packagePort = packagePort;
    }

    public ChannelHandler getFileReqHandler() {
        return fileReqHandler;
    }

    public void setFileReqHandler(ChannelHandler fileReqHandler) {
        this.fileReqHandler = fileReqHandler;
    }


}
在上述类中定义的ChannelHandler fileReqHandler如下所示:

File file  = new File("file1.zip");
ChunkedFile chunkedFile;
try {
    chunkedFile = new ChunkedFile(file);
    client.send(chunkedFile);
} catch (IOException e) {
    e.printStackTrace();
}
import java.io.File;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.stream.ChunkedFile;
import io.netty.util.ReferenceCountUtil;

public class FileChunkReqWriteHandler extends SimpleChannelInboundHandler<ChunkedFile> {
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("in channel active method");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();

        if (ctx.channel().isActive()) {
            ctx.writeAndFlush("ERR: " +
                    cause.getClass().getSimpleName() + ": " +
                    cause.getMessage() + '\n').addListener(ChannelFutureListener.CLOSE);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ChunkedFile msg)
            throws Exception {
        System.out.println("in channelRead0");

    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);
    }

}

我已重写channelRead方法来读取文件。问题是channelRead方法在不确定循环中被调用,每次只读取少量字节。如何知道客户端发送的整个数据何时已被读取?我想读取从客户端发送的全部数据,并重新构造压缩文件。如何实现这一点?

您需要以某种方式检测文件的结尾。例如,您可以编写自己的协议,该协议始终将文件的预期长度编码为long,并在接收端读取该协议,以了解何时接收到结尾。

我尝试读取字节块,追加到大小与要发送的文件大小相同的字节数组,并尝试使用FileOutputStream重新创建文件。但是这样创建的文件没有打开,它是一个无效文件。是否有其他方法可以重新创建zip文件及其内容。请您快速浏览一下服务器和客户端代码,如果我遗漏了什么,请告诉我好吗?除了使用ChunkedFile之外,还有其他方法可以实现此文件传输吗?