问题描述:
因为某些极端网络环境,导致我传文件非常非常不方便,所以想到写了这么一个小工具,进行点对点的文件传输。现已放到github,https://github.com/chengpei/file-transfer
开发过程中遇到一个奇怪的问题,在我接收完了文件内容后,准备发送一个文件接收完成的指令,结果并没有发送出去,也就是下面倒数第26行
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!showProgressThread.isAlive()) {
sending = true;
startTime = System.currentTimeMillis();
showProgressThread.start();
}
ByteBuf byteBuf = (ByteBuf) msg;
int readableBytes = byteBuf.readableBytes();
byte[] bytes = new byte[readableBytes];
byteBuf.readBytes(bytes);
fos.write(bytes);
byteBuf.release();
totalSize += readableBytes;
count++;
if (totalSize == prepareSendFileCommand.getFileSize()) {
if (fos != null) {
fos.close();
sending = false;
log.info("传输结束,耗时: {},平均速度:{}/s", getTimeStr(System.currentTimeMillis() - startTime), getNetFileSizeDescription(totalSize / (System.currentTimeMillis() - startTime) / 1000));
}
ctx.pipeline().remove(this);
CompleteFileReceiveCommand completeFileReceiveCommand = new CompleteFileReceiveCommand();
completeFileReceiveCommand.setPrepareSendFileCommand(prepareSendFileCommand);
completeFileReceiveCommand.setElapsedTime(System.currentTimeMillis() - startTime);
ctx.writeAndFlush(completeFileReceiveCommand);
ConsoleManager.getInstance().finshRunningTask(prepareSendFileCommand.getTaskId());
}
}
原因分析:
这里发送的是一个Command对象,没有发送出去很可能是没有经过对应的编码器,当前这个handler是为了接收文件内容特地追加到pipeline链的最前端了,因为接收的文件不需要解码,直接写入文件即可,写完文件这个handler也会移除掉,方便接收后续指令解码。突然想到这里write是不是消息没有传递到pipeline的尾端,直接从当前的handler发回去了,这样就无法经过定义的CommandToByteEncoder编码器了,太久没用Netty了,一时没注意到这个细节。
解决方案:
使用pipeline的writeAndFlush方法就可以了,它的writeAndFlush可以直接从pipeline尾端发送,就可以经过所有的编码器了,替换为以下代码即可
ctx.pipeline().writeAndFlush(completeFileReceiveCommand);
评论区