我想从客户端向服务器发送一个大型zip文件,然后从服务器到客户端获得收到该文件的回复。我正在使用io.netty.handler.stream.ChunkedWriteHandler
发送大文件。我的问题是如何知道服务器何时收到整个数据,因为在服务器端,读取数据的代码似乎无限期地运行。客户端和服务器端的代码如下:
客户端代码是:
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);
}
}
此类的方法send(final ChunkedFile file)
用于发送文件。它的名称如下:
File file = new File("file1.zip");
ChunkedFile chunkedFile;
try {
chunkedFile = new ChunkedFile(file);
client.send(chunkedFile);
} catch (IOException e) {
e.printStackTrace();
}
服务器端代码是:
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)如下:
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方法在无限循环中被调用,每次只读取少量字节。如何知道客户端发送的整个数据何时被读取?我想阅读从客户端发送的整个数据并重新构建压缩文件。我怎样才能做到这一点?
答案 0 :(得分:0)
您需要以某种方式检测文件的结尾。例如,您可以编写自己的协议,该协议始终具有文件的预期长度,并且在接收端读取此信息以了解接收结束的时间。