问题描述
我正在尝试从服务器向客户端发送文件,即从服务器请求的客户端。
客户端在 FileRequestProtocol
中对文件进行拼写,将其发送到服务器,服务器将文件大小添加到文件 FileRequestProtocol
并将其返回给客户端。
I'm trying to send a file, a client requested from the server, from the server to the client.The Client specefies the file in the FileRequestProtocol
, sends it to the server, the server adds the file size to file FileRequestProtocol
and returns it to the client.
客户端使用正确的文件大小添加新的 FileChunkReqWriteHandler
到它的管道。
The client adds a new FileChunkReqWriteHandler
with the correct file size to its pipeline.
服务器用上下文和所需文件创建一个新的 ChunkedFileServerHandler
并尝试发送它,但 FileChunkReqWriteHandler
永远不会从频道读取字节。
The server creates a new ChunkedFileServerHandler
with the context and the desired file and tries to send it, but the FileChunkReqWriteHandler
never reads byte from the channel.
我在这里做错了什么?
日志
INFO ProtocolHeadHandler:48 - Client send ProtocolHead [version=1, jobType=FILEREQUEST]
INFO ProtocolHeadServerHandler:36 - Server receive ProtocolHead [version=1, jobType=FILEREQUEST]
INFO ProtocolHeadHandler:57 - Client ProtocolHead equals, Send Protocol FileRequestProtocol [filePath=test.jpg, fileSize=0]
INFO FileRequestServerHandler:42 - Server new FileRequest FileRequestProtocol [filePath=test.jpg, fileSize=0]
INFO FileRequestHandler:41 - Client receives FileRequestProtocol [filePath=test.jpg, fileSize=174878]
INFO ChunkedFileServerHandler:39 - New ChunkedFileServerHandler
INFO FileChunkReqWriteHandler:20 - New ChunkedFile Handler FileRequestProtocol [filePath=test.jpg, fileSize=174878]
客户
FileRequestHandler.java
FileRequestHandler.java
public class FileRequestHandler extends
SimpleChannelInboundHandler<FileRequestProtocol> {
private Logger logger = Logger.getLogger(this.getClass());
public FileRequestHandler() {
}
@Override
public void channelRead0(ChannelHandlerContext ctx, FileRequestProtocol msg) {
logger.info("Client receives " + msg);
ReferenceCountUtil.release(msg);
ctx.channel().pipeline().addLast(new FileChunkReqWriteHandler(msg));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
logger.info("Client read complete");
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
FileChunkReqWriteHandler.java
FileChunkReqWriteHandler.java
public class FileChunkReqWriteHandler extends SimpleChannelInboundHandler<ChunkedFile> {
FileRequestProtocol fileRequestProtocol;
private Logger logger = Logger.getLogger(this.getClass());
public FileChunkReqWriteHandler(FileRequestProtocol msg) {
this.fileRequestProtocol = msg;
logger.info("New ChunkedFile Handler " + msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
logger.info("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 {
logger.info("in channelRead0");
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info("channelRead");
ByteBuf buf = (ByteBuf) msg;
byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);
if(buf.readableBytes() >= this.fileRequestProtocol.getFileSize())
{
logger.info("received all data");
}
}
}
服务器
FileRequestServerHandler.java
FileRequestServerHandler.java
public class FileRequestServerHandler extends
SimpleChannelInboundHandler<FileRequestProtocol> {
private File f;
private Logger logger = Logger.getLogger(this.getClass());
@Override
public void channelRead0(ChannelHandlerContext ctx, FileRequestProtocol fileRequest) {
logger.info("Server new FileRequest " + fileRequest);
f = new File(fileRequest.getFilePath());
fileRequest.setFileSize(f.length());
ctx.writeAndFlush(fileRequest);
new ChunkedFileServerHandler(ctx,f);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
logger.info("Server read complete");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
ChunkedFileServerHandler.java
ChunkedFileServerHandler.java
public class ChunkedFileServerHandler extends ChunkedWriteHandler {
private Logger logger = Logger.getLogger(this.getClass());
private File file;
public ChunkedFileServerHandler(ChannelHandlerContext ctx, File file) {
this.file = file;
logger.info("New ChunkedFileServerHandler");
ChunkedFile chunkedFile;
try {
chunkedFile = new ChunkedFile(this.file);
ctx.writeAndFlush(chunkedFile);
ctx.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
logger.info("FILE WRITE GETS ACTIVE");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
更新
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast("encoder", new ObjectEncoder());
p.addLast("decoder",
new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
p.addLast("protocolhead", new ProtocolHeadServerHandler());
p.addLast("filerequestserverhandler", new FileRequestServerHandler());
p.addLast("chunkedfileserver", new ChunkedFileServerHandler());
}
}
服务器启动
public void startUp()
{
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ServerInitializer());
// Bind and start to accept incoming connections.
b.bind(this.port).sync().channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
推荐答案
那里我可以看到两部分:
There are 2 parts I can see:
1)你不应该在你自己的处理程序中创建一个新的处理程序,而是直接创建ChunkedFile并编写它:
1) You shouldn't create a new handler within your own handler, but directly create the ChunkedFile and write it:
public class FileRequestServerHandler extends
SimpleChannelInboundHandler<FileRequestProtocol> {
private File f;
private Logger logger = Logger.getLogger(this.getClass());
@Override
public void channelRead0(ChannelHandlerContext ctx, FileRequestProtocol fileRequest) {
logger.info("Server new FileRequest " + fileRequest);
f = new File(fileRequest.getFilePath());
fileRequest.setFileSize(f.length());
ctx.writeAndFlush(fileRequest);
// directly make your chunkedFile there instead of creating a sub handler
chunkedFile = new ChunkedFile(this.file);
ctx.writeAndFlush(chunkedFile);// need a specific handler
// Don't create such an handler: new ChunkedFileServerHandler(ctx,f);
}
2)由于你使用ChunkedInput(这里是ChunkedFile)编写,你必须拥有你的管道在你的处理程序之前是一个ChunkedWriteHandler,所以你的初始化程序看起来像:
2) Since you write using ChunkedInput (here ChunkedFile), you must have in your pipeline a ChunkedWriteHandler before your handler, so your Initializer could look like:
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast("encoder", new ObjectEncoder());
p.addLast("decoder",
new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
p.addLast("chunkedWriteHandler", new ChunkedWriteHandler());// added
p.addLast("protocolhead", new ProtocolHeadServerHandler());
p.addLast("filerequestserverhandler", new FileRequestServerHandler());
// removed: p.addLast("chunkedfileserver", new ChunkedFileServerHandler());
}
}
ChunkedWriteHandler的位置
可以更改,但总是在您自己的处理程序之前写入 ChunkedFile
。
The position of the ChunkedWriteHandler
could be changed, but always before your own handler where you write the ChunkedFile
.
3)最后注意事项:看看并注意你的编码器/解码器(ObjectEncoder / ObjectDecoder),因为我不能100%确定他们是否可以与文件一起编写/读取ByteBuf。
它可能有效,或者不是......
3) Final note: have a look and take care of your Encoder/Decoder (ObjectEncoder/ObjectDecoder) since I'm not 100% sure if they can collaborate with such write/read of ByteBuf from/to a file.It may work, or not...
这篇关于使用Netty.io将文件从服务器发送到客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!