无法使用netty发送大型zip文件
我想从客户机向服务器发送一个大的zip文件,然后从服务器向客户机发送一个收到该文件的回复。我正在使用io.netty.handler.stream.ChunkedWriteHandler发送大文件。我的问题是如何知道服务器何时接收到整个数据,因为在服务器端,读取数据的代码似乎无限期地运行。客户端和服务器端的代码如下:无法使用netty发送大型zip文件,netty,Netty,我想从客户机向服务器发送一个大的zip文件,然后从服务器向客户机发送一个收到该文件的回复。我正在使用io.netty.handler.stream.ChunkedWriteHandler发送大文件。我的问题是如何知道服务器何时接收到整个数据,因为在服务器端,读取数据的代码似乎无限期地运行。客户端和服务器端的代码如下: File file = new File("file1.zip"); ChunkedFile chunkedFile; try { chunkedFile = new C
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之外,还有其他方法可以实现此文件传输吗?