Netty处理器的小和Netty大文件传输方法思路
使用一个解析处理器,对上传的请求进行解析,对特定的请求进行解析,再在pipeline后面加上指定的handler理器
-
-
((FullHttpRequest) msg).release();
-
-
ctx.fireChannelRead(msg);
-
-
ctx.channel().pipeline().remove(this);
-
-
pipeline.addAfter(new Process());
-
-
public class ParseRequestHandler extends ChannelInboundHandlerAdapter {
-
-
大文件传输方法的思路
大文件传输我这里在原来的Netty文件传输之上进行了修改,本质原因是文件太多,不能一次传完,需要分多次进行传输。
-
使用了ChunkedWriteHandler,对文件信息进行了分包处理,使得文件传输压力减小,其次保证了文件的安全性
-
对大文件进行分片读取,读取生成一个指定的小文件,再发送小文件。(实现了大文件向小文件的过渡)最后再删除小文件即可
-
客户端使用了序号进行区分信息,被一个小文件都带有一个序号,用于区分文件地址。客户端每次发送一个序号,服务器返回一个指定位置的指定长度的小文件,客户端再对序号加一,请求服务器,直到服务器完全传输完毕。
-
package ProcessRequest;
-
-
-
import java.io.IOException;
-
import java.io.RandomAccessFile;
-
import java.net.URLDecoder;
-
import java.net.URLEncoder;
-
-
import org.apache.log4j.Logger;
-
import Utility.ExecutorGroup;
-
import Utility.FileHandlerFunction;
-
import Utility.HTTPDefineConstant;
-
import Utility.HTTPResponse;
-
import io.netty.channel.ChannelFuture;
-
import io.netty.channel.ChannelHandlerContext;
-
import io.netty.channel.ChannelInboundHandlerAdapter;
-
import io.netty.channel.ChannelProgressiveFuture;
-
import io.netty.channel.ChannelProgressiveFutureListener;
-
import io.netty.handler.codec.http.FullHttpRequest;
-
import io.netty.handler.codec.http.HttpChunkedInput;
-
import io.netty.handler.codec.http.HttpResponse;
-
import io.netty.handler.codec.http.HttpResponseStatus;
-
import io.netty.handler.stream.ChunkedFile;
-
import io.netty.handler.stream.ChunkedWriteHandler;
-
import io.netty.util.concurrent.EventExecutorGroup;
-
-
public class DownloadOneHugeFileProcess extends ChannelInboundHandlerAdapter{
-
// 日志
-
private static final Logger logger = Logger.getLogger(DownloadOneHugeFileProcess.class);
-
-
private String userID = "";
-
-
private ChannelHandlerContext ctx = null;
-
-
// 执行耗时操作的线程池
-
private EventExecutorGroup group = ExecutorGroup.getInstance().getExecutorGroup();
-
-
private String fileName;
-
-
//客户端发送的需要返回的文件里面序号段,这里序号段从0开始传输文件
-
private long sequenceNumber = 0;
-
-
private int dataPackageNumber = 0;
-
-
// 设置为每次传输5m大小的数据,实现单个文件速度的快递提高,让客户端能马上获得文件
-
// 让客户端马上能播放文件,实现一边播放一边下载
-
private final int chunkSize = 5*1024*1024;
-
-
private RandomAccessFile downloadFile;
-
-
-
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
-
this.ctx = ctx;
-
this.userID = "" ctx.channel().remoteAddress();
-
}
-
-
-
public void channelActive(ChannelHandlerContext ctx) throws Exception {
-
this.ctx = ctx;
-
this.userID = "" ctx.channel().remoteAddress();
-
}
-
-
-
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-
if (msg instanceof FullHttpRequest) {
-
FullHttpRequest request = (FullHttpRequest) msg;
-
// 获取请求方法名
-
String method = request.method().toString();
-
// 下载文件(2022-03-25)
-
if ("DownloadOneFileRequest".equals(method)) {
-
System.out.println("DownloadOneHugeFileRequest Process");
-
-
/*
-
* 服务器根据客户端发送的数据序号,从文件中截取指定长度的文件发送回客户端
-
* */
-
fileName =URLDecoder.decode(request.headers().get("oneFileName"), "UTF-8");
-
System.out.println("下载的文件名" fileName);
-
sequenceNumber = Long.parseLong(request.headers().get("sequenceNumber"));
-
startSend(System.getProperty("user.dir") "/AudioAndVideo/" fileName, "668");
-
-
((FullHttpRequest) msg).release();
-
} else {
-
// 激活下一个Handler
-
ctx.fireChannelRead(msg);
-
ctx.channel().pipeline().remove(this);
-
}
-
-
} else {
-
ctx.fireChannelRead(msg);
-
}
-
}
-
-
-
-
public void startSend(String path, String statusCode) {
-
// 提交耗时任务给线程池
-
group.submit(new Runnable() {
-
-
public void run() {
-
try {
-
-
/*
-
*downloadFile的内置开始位置在getContent()中设置
-
*这个文件在等全部分包完成再关闭吧
-
* */
-
downloadFile = new RandomAccessFile(path, "r");
-
-
long fileLen = downloadFile.length();
-
-
// 文件不为空且文件长度小于0
-
if (fileLen < 0 && downloadFile != null) {
-
logger.error("读取待批改文件遇到异常!");
-
downloadFile.close();
-
}
-
else {
-
-
dataPackageNumber = (int) (fileLen/(chunkSize));
-
int tem = (int) (fileLen%(chunkSize) );
-
if(tem != 0) {
-
//有余数
-
dataPackageNumber ;
-
}
-
}
-
//生成一个临时文件
-
sendHugeFile(statusCode,sequenceNumber,createOnePartSmallFile());
-
-
} catch (IOException e) {
-
logger.error(e);
-
e.printStackTrace();
-
}
-
}
-
});
-
}
-
-
private void sendHugeFile( String statusCode ,long number, RandomAccessFile temFile) throws IOException {
-
-
HttpResponseStatus status = null;
-
switch (statusCode) {
-
case "668":
-
status = HTTPDefineConstant.DOWNLOAD_ONEFILE_SUCCESS;
-
break;
-
case "669":
-
status = HTTPDefineConstant.DOWNLOAD_ONEFILE_FAIL;
-
break;
-
default:
-
break;
-
}
-
-
if (null == ctx.pipeline().get(ChunkedWriteHandler.class)) {
-
ctx.pipeline().addBefore("downloadOneHugeFile", "chunked writer", new ChunkedWriteHandler());
-
}
-
-
ChannelFuture sendFileFuture;
-
HttpResponse response;
-
if(number != dataPackageNumber-1)
-
{
-
response = HTTPResponse.downloadOneHugeFileResponse(status, temFile.length() , URLEncoder.encode(fileName, "UTF-8") , String.valueOf(number) , "NO");
-
ctx.write(response);
-
}else {
-
logger.info("sequenceNumber 文件包序号为:" number " 为最后一个文件包");
-
response = HTTPResponse.downloadOneHugeFileResponse(status, temFile.length() , URLEncoder.encode(fileName, "UTF-8") , String.valueOf(number) , "YES");
-
ctx.write(response);
-
}
-
sendFileFuture = ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(temFile,0, (long)temFile.length(),(int)temFile.length()) ), ctx.newProgressivePromise());
-
-
sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
-
-
public void operationComplete(ChannelProgressiveFuture future) throws Exception {
-
if (future.isSuccess()) {
-
try {
-
temFile.close();
-
logger.info("downloadFile1文件关闭成功");
-
} catch (IOException e) {
-
logger.error("downloadFile文件关闭出现异常:" e);
-
}
-
// try {
-
// temFile.write(new byte[] {1, 2, 3});
-
//
-
// } catch (IOException e) {
-
// e.printStackTrace(); //如果流已经关闭,这里会报
-
// }
-
//进行删除文件的操作
-
String temFilePath = System.getProperty("user.dir") "/AudioAndVideo/" number fileName;
-
if(FileHandlerFunction.delete(temFilePath))
-
{
-
System.out.println("成功删除:" temFilePath);
-
}else {
-
System.out.println("删除失败:" temFilePath);
-
-
}
-
-
if(number == dataPackageNumber-1)
-
{
-
try {
-
downloadFile.close();
-
logger.info("最后一个downloadFile文件关闭成功");
-
} catch (IOException e) {
-
logger.error("downloadFile文件关闭出现异常:" e);
-
}
-
-
logger.info("下载文件 :" temFile.getFD() " 传输完毕\n接收用户:" userID);
-
ctx.pipeline().remove("downloadOneHugeFile");
-
ctx.pipeline().remove("chunked writer");
-
}
-
}
-
else {//发送失败的情况,重新发送
-
sendHugeFile(statusCode,number,temFile);
-
}
-
}
-
-
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total)
-
throws Exception {
-
}
-
});
-
-
-
}
-
-
-
-
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
-
logger.error(cause);
-
}
-
-
private RandomAccessFile createOnePartSmallFile() throws IOException
-
{
-
long fileLen = downloadFile.length();
-
// logger.info("客户端请求传输大文件 fileLen:" fileLen);
-
// logger.info("客户端请求传输大文件 dataPackageNumber:" dataPackageNumber);
-
-
String temFilePath = System.getProperty("user.dir") "/AudioAndVideo/" sequenceNumber fileName;
-
RandomAccessFile temFile = null;
-
try {
-
temFile = new RandomAccessFile(temFilePath, "rw");
-
} catch (IOException e) {
-
logger.error("文件打开出现异常:" e);
-
}
-
temFile.seek(0);
-
-
if(dataPackageNumber-1 != sequenceNumber )
-
{
-
logger.info("生成下载文件,文件序号为:" sequenceNumber);
-
temFile.write(getContent(sequenceNumber*chunkSize,chunkSize, downloadFile));
-
}
-
else {
-
-
int tem1 = (int) (fileLen%(chunkSize) );
-
if(tem1 != 0) {
-
//有余数
-
logger.info("生成最后一个文件,有余数,文件序号为:" sequenceNumber);
-
long temChunkSize = fileLen-(sequenceNumber*chunkSize);
-
temFile.write(getContent(sequenceNumber*temChunkSize,temChunkSize, downloadFile));
-
-
}else {
-
//无余数
-
logger.info("生成最后一个文件,无余数,文件序号为:" sequenceNumber);
-
temFile.write(getContent(sequenceNumber*chunkSize,chunkSize, downloadFile));
-
-
}
-
}
-
-
return temFile;
-
}
-
-
-
private byte[] getContent(long off , long len, RandomAccessFile downloadFile) throws IOException {
-
downloadFile.seek(off);
-
byte[] bytes = new byte[(int) len];
-
downloadFile.read(bytes,(int)0, (int)len);
-
return bytes;
-
}
-
-
}
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfkfefc
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01