温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么使用java Netty实现传输文件、分片发送、断点续传

发布时间:2021-11-18 10:16:25 阅读:620 作者:iii 栏目:编程语言
Java开发者专用服务器限时活动,0元免费领,库存有限,领完即止! 点击查看>>

这篇文章主要讲解了“怎么使用java Netty实现传输文件、分片发送、断点续传”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用java Netty实现传输文件、分片发送、断点续传”吧!

开发环境

1、jdk1.8【jdk1.7以下只能部分支持netty】
2、Netty4.1.36.Final【netty3.x 4.x 5每次的变化较大,接口类名也随着变化】

代码示例

itstack-demo-netty-2-04└── src    ├── main    │   └── java    │       └── org.itstack.demo.netty    │           ├── client    │           │   ├── MyChannelInitializer.java    │           │   ├── MyClientHandler.java    │           │   └── NettyClient.java    │           ├── codec    │           │   ├── ObjDecoder.java    │           │   └── ObjEncoder.java    │           ├── domain    │           │   ├── Constants.java    │           │   ├── FileBurstData.java    │           │   ├── FileBurstInstruct.java    │           │   ├── FileDescInfo.java    │           │   └── FileTransferProtocol.java    │           ├── server    │           │   ├── MyChannelInitializer.java    │           │   ├── MyServerHandler.java    │           │   └── NettyServer.java    │           └── util    │               ├── CacheUtil.java    │               ├── FileUtil.java    │               ├── MsgUtil.java    │               └── SerializationUtil.java    │    └── test         └── java             └── org.itstack.demo.test                 ├── ApiTest.java                 ├── NettyClientTest.java                 └── NettyServerTest.java

演示部分重点代码块,完整代码下载关注公众号;bugstack虫洞栈

client/MyClientHandler.java *文件客户端;channelRead处理文件协议,其中模拟传输过程中断,场景测试可以注释掉

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {    //数据格式验证    if (!(msg instanceof FileTransferProtocol)) return;    FileTransferProtocol fileTransferProtocol = (FileTransferProtocol) msg;    //0传输文件'请求'1文件传输'指令'2文件传输'数据'    switch (fileTransferProtocol.getTransferType()) {        case 1:            FileBurstInstruct fileBurstInstruct = (FileBurstInstruct) fileTransferProtocol.getTransferObj();            //Constants.FileStatus {0开始、1中间、2结尾、3完成}            if (Constants.FileStatus.COMPLETE == fileBurstInstruct.getStatus()) {                ctx.flush();                ctx.close();                System.exit(-1);                return;            }            FileBurstData fileBurstData = FileUtil.readFile(fileBurstInstruct.getClientFileUrl(), fileBurstInstruct.getReadPosition());            ctx.writeAndFlush(MsgUtil.buildTransferData(fileBurstData));            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack虫洞栈客户端传输文件信息。FILE:" + fileBurstData.getFileName() + " SIZE(byte):" + (fileBurstData.getEndPos() - fileBurstData.getBeginPos()));            break;        default:            break;    }    /**模拟传输过程中断,场景测试可以注释掉     *     */    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack虫洞栈客户端传输文件信息[主动断开链接,模拟断点续传]");    ctx.flush();    ctx.close();    System.exit(-1);}

domain/FileBurstData.java *文件分片数据块

/** * 文件分片数据 * 虫洞栈:https://bugstack.cn * 公众号:bugstack虫洞栈  {获取学习源码} * 虫洞群:①群5398358 ②群5360692 * Create by fuzhengwei on 2019 */public class FileBurstData {    private String fileUrl;     //客户端文件地址    private String fileName;    //文件名称    private Integer beginPos;   //开始位置    private Integer endPos;     //结束位置    private byte[] bytes;       //文件字节;再实际应用中可以使用非对称加密,以保证传输信息安全    private Integer status;     //Constants.FileStatus0开始、1中间、2结尾、3完成}    ... get/set}

domain/FileBurstInstruct.java *文件分片指令

/** * 文件分片指令 * 虫洞栈:https://bugstack.cn * 公众号:bugstack虫洞栈  {获取学习源码} * 虫洞群:①群5398358 ②群5360692 * Create by fuzhengwei on @2019 */public class FileBurstInstruct {    private Integer status;       //Constants.FileStatus0开始、1中间、2结尾、3完成}    private String clientFileUrl; //客户端文件URL    private Integer readPosition; //读取位置    ... get/set}

domain/FileDescInfo.java *文件传输信息

/** * 文件描述信息 * 虫洞栈:https://bugstack.cn * 公众号:bugstack虫洞栈  {获取学习源码} * 虫洞群:①群5398358 ②群5360692 * Create by fuzhengwei on @2019 */public class FileDescInfo {    private String fileUrl;    private String fileName;    private Long fileSize;    ... get/set}

domain/FileTransferProtocol.java *文件传输协议

/** * 文件传输协议 * 虫洞栈:https://bugstack.cn * 公众号:bugstack虫洞栈  {获取学习源码} * 虫洞群:5360692 * Create by fuzhengwei on @2019 */public class FileTransferProtocol {    private Integer transferType; //0请求传输文件、1文件传输指令、2文件传输数据    private Object transferObj;   //数据对象;(0)FileDescInfo、(1)FileBurstInstruct、(2)FileBurstData    ... get/set}

serverMyServerHandler.java *文件服务端;channelRead处理文件协议,并包含了保存续传信息,用于断点续传

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {    //数据格式验证    if (!(msg instanceof FileTransferProtocol)) return;    FileTransferProtocol fileTransferProtocol = (FileTransferProtocol) msg;    //0传输文件'请求'1文件传输'指令'2文件传输'数据'    switch (fileTransferProtocol.getTransferType()) {        case 0:            FileDescInfo fileDescInfo = (FileDescInfo) fileTransferProtocol.getTransferObj();            //断点续传信息,实际应用中需要将断点续传信息保存到数据库中            FileBurstInstruct fileBurstInstructOld = CacheUtil.burstDataMap.get(fileDescInfo.getFileName());            if (null != fileBurstInstructOld) {                if (fileBurstInstructOld.getStatus() == Constants.FileStatus.COMPLETE) {                    CacheUtil.burstDataMap.remove(fileDescInfo.getFileName());                }                //传输完成删除断点信息                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack虫洞栈服务端,接收客户端传输文件请求[断点续传]。" + JSON.toJSONString(fileBurstInstructOld));                ctx.writeAndFlush(MsgUtil.buildTransferInstruct(fileBurstInstructOld));                return;            }            //发送信息            FileTransferProtocol sendFileTransferProtocol = MsgUtil.buildTransferInstruct(Constants.FileStatus.BEGIN, fileDescInfo.getFileUrl(), 0);            ctx.writeAndFlush(sendFileTransferProtocol);            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack虫洞栈服务端,接收客户端传输文件请求。" + JSON.toJSONString(fileDescInfo));            break;        case 2:            FileBurstData fileBurstData = (FileBurstData) fileTransferProtocol.getTransferObj();            FileBurstInstruct fileBurstInstruct = FileUtil.writeFile("E://", fileBurstData);            //保存断点续传信息            CacheUtil.burstDataMap.put(fileBurstData.getFileName(), fileBurstInstruct);            ctx.writeAndFlush(MsgUtil.buildTransferInstruct(fileBurstInstruct));            System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " bugstack虫洞栈服务端,接收客户端传输文件数据。" + JSON.toJSONString(fileBurstData));            //传输完成删除断点信息            if (fileBurstInstruct.getStatus() == Constants.FileStatus.COMPLETE) {                CacheUtil.burstDataMap.remove(fileBurstData.getFileName());            }            break;        default:            break;    }}

util/FileUtil.java *文件读写工具,分片读取写入处理类

/** * 文件读写工具 * 虫洞栈:https://bugstack.cn * 公众号:bugstack虫洞栈  {获取学习源码} * 虫洞群:5360692 * Create by fuzhengwei on @2019 */public class FileUtil {    public static FileBurstData readFile(String fileUrl, Integer readPosition) throws IOException {        File file = new File(fileUrl);        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");//r: 只读模式 rw:读写模式        randomAccessFile.seek(readPosition);        byte[] bytes = new byte[1024];        int readSize = randomAccessFile.read(bytes);        if (readSize <= 0) {            randomAccessFile.close();            return new FileBurstData(Constants.FileStatus.COMPLETE);//Constants.FileStatus0开始、1中间、2结尾、3完成}        }        FileBurstData fileInfo = new FileBurstData();        fileInfo.setFileUrl(fileUrl);        fileInfo.setFileName(file.getName());        fileInfo.setBeginPos(readPosition);        fileInfo.setEndPos(readPosition + readSize);        //不足1024需要拷贝去掉空字节        if (readSize < 1024) {            byte[] copy = new byte[readSize];            System.arraycopy(bytes, 0, copy, 0, readSize);            fileInfo.setBytes(copy);            fileInfo.setStatus(Constants.FileStatus.END);        } else {            fileInfo.setBytes(bytes);            fileInfo.setStatus(Constants.FileStatus.CENTER);        }        randomAccessFile.close();        return fileInfo;    }    public static FileBurstInstruct writeFile(String baseUrl, FileBurstData fileBurstData) throws IOException {        if (Constants.FileStatus.COMPLETE == fileBurstData.getStatus()) {            return new FileBurstInstruct(Constants.FileStatus.COMPLETE); //Constants.FileStatus0开始、1中间、2结尾、3完成}        }        File file = new File(baseUrl + "/" + fileBurstData.getFileName());        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");//r: 只读模式 rw:读写模式        randomAccessFile.seek(fileBurstData.getBeginPos());      //移动文件记录指针的位置,        randomAccessFile.write(fileBurstData.getBytes());        //调用了seek(start)方法,是指把文件的记录指针定位到start字节的位置。也就是说程序将从start字节开始写数据        randomAccessFile.close();        if (Constants.FileStatus.END == fileBurstData.getStatus()) {            return new FileBurstInstruct(Constants.FileStatus.COMPLETE); //Constants.FileStatus0开始、1中间、2结尾、3完成}        }        //文件分片传输指令        FileBurstInstruct fileBurstInstruct = new FileBurstInstruct();        fileBurstInstruct.setStatus(Constants.FileStatus.CENTER);            //Constants.FileStatus {0开始、1中间、2结尾、3完成}        fileBurstInstruct.setClientFileUrl(fileBurstData.getFileUrl());      //客户端文件URL        fileBurstInstruct.setReadPosition(fileBurstData.getEndPos() + 1);    //读取位置        return fileBurstInstruct;    }}

util/MsgUtil.java *传输消息体构建工具类

/** * 消息构建工具 * 虫洞栈:https://bugstack.cn * 公众号:bugstack虫洞栈  {获取学习源码} * 虫洞群:5360692 * Create by fuzhengwei on @2019 */public class MsgUtil {    /**     * 构建对象;请求传输文件(客户端)     *     * @param fileUrl  客户端文件地址     * @param fileName 文件名称     * @param fileSize 文件大小     * @return 传输协议     */    public static FileTransferProtocol buildRequestTransferFile(String fileUrl, String fileName, Long fileSize) {        FileDescInfo fileDescInfo = new FileDescInfo();        fileDescInfo.setFileUrl(fileUrl);        fileDescInfo.setFileName(fileName);        fileDescInfo.setFileSize(fileSize);        FileTransferProtocol fileTransferProtocol = new FileTransferProtocol();        fileTransferProtocol.setTransferType(0);//0请求传输文件、1文件传输指令、2文件传输数据        fileTransferProtocol.setTransferObj(fileDescInfo);        return fileTransferProtocol;    }    /**     * 构建对象;文件传输指令(服务端)     * @param status          0请求传输文件、1文件传输指令、2文件传输数据     * @param clientFileUrl   客户端文件地址     * @param readPosition    读取位置     * @return                传输协议     */    public static FileTransferProtocol buildTransferInstruct(Integer status, String clientFileUrl, Integer readPosition) {        FileBurstInstruct fileBurstInstruct = new FileBurstInstruct();        fileBurstInstruct.setStatus(status);        fileBurstInstruct.setClientFileUrl(clientFileUrl);        fileBurstInstruct.setReadPosition(readPosition);        FileTransferProtocol fileTransferProtocol = new FileTransferProtocol();        fileTransferProtocol.setTransferType(Constants.TransferType.INSTRUCT); //0传输文件'请求'、1文件传输'指令'、2文件传输'数据'        fileTransferProtocol.setTransferObj(fileBurstInstruct);        return fileTransferProtocol;    }    /**     * 构建对象;文件传输指令(服务端)     *     * @return 传输协议     */    public static FileTransferProtocol buildTransferInstruct(FileBurstInstruct fileBurstInstruct) {        FileTransferProtocol fileTransferProtocol = new FileTransferProtocol();        fileTransferProtocol.setTransferType(Constants.TransferType.INSTRUCT);  //0传输文件'请求'、1文件传输'指令'、2文件传输'数据'        fileTransferProtocol.setTransferObj(fileBurstInstruct);        return fileTransferProtocol;    }    /**     * 构建对象;文件传输数据(客户端)     *     * @return 传输协议     */    public static FileTransferProtocol buildTransferData(FileBurstData fileBurstData) {        FileTransferProtocol fileTransferProtocol = new FileTransferProtocol();        fileTransferProtocol.setTransferType(Constants.TransferType.DATA); //0传输文件'请求'1文件传输'指令'2文件传输'数据'        fileTransferProtocol.setTransferObj(fileBurstData);        return fileTransferProtocol;    }}

test/NettyServerTest.java *服务端启动器

/** * 虫洞栈:https://bugstack.cn * 公众号:bugstack虫洞栈  {获取学习源码} * 虫洞群:①群5398358 ②群5360692 * Create by fuzhengwei on 2019 */public class NettyServerTest {    public static void main(String[] args) {        //启动服务        new NettyServer().bing(7397);    }}

test/NettyClientTest.java *客户端启动器

/** * 虫洞栈:https://bugstack.cn * 公众号:bugstack虫洞栈  {获取学习源码} * 虫洞群:①群5398358 ②群5360692 * Create by fuzhengwei on 2019 */public class NettyClientTest {    public static void main(String[] args) {        //启动客户端        ChannelFuture channelFuture = new NettyClient().connect("127.0.0.1", 7397);        //文件信息{文件大于1024kb方便测试断点续传}        File file = new File("C:\\Users\\fuzhengwei\\Desktop\\测试传输文件.rar");        FileTransferProtocol fileTransferProtocol = MsgUtil.buildRequestTransferFile(file.getAbsolutePath(), file.getName(), file.length());        //发送信息;请求传输文件        channelFuture.channel().writeAndFlush(fileTransferProtocol);    }}

测试结果

启动NettyServerTest *默认接收地址为E盘根目录

怎么使用java Netty实现传输文件、分片发送、断点续传

启动NettyClientTest *设置传输文件

怎么使用java Netty实现传输文件、分片发送、断点续传

文件传输结果

怎么使用java Netty实现传输文件、分片发送、断点续传

服务端执行结果

itstack-demo-netty server start done. {关注公众号:bugstack虫洞栈,获取源码}链接报告开始链接报告信息:有一客户端链接到本服务端channelId:3a1df8c1链接报告IP:127.0.0.1链接报告Port:7397链接报告完毕2019-08-04 19:46:46 bugstack虫洞栈服务端,接收客户端传输文件请求{"fileName":"测试传输文件.rar","fileSize":1400,"fileUrl":"C:\\Users\\fuzhengwei1\\Desktop\\测试传输文件.rar"}2019-08-04 19:46:46 bugstack虫洞栈服务端,接收客户端传输文件数据{"beginPos":0,"bytes":"UmFyIRoHAM+QcwAADQAAAAAAAAC4C3SgkkkAFAUAAIjDEQACJRsHe0WECE8dMyQAIAAAALLiytS0q8rkzsS8/i50eHQAbWpL1YsgT5OPoIdl9k4udAB4dACwS2heCZgVEQzPzUEXfAnhs2R75rhNbCQhNE3uMY4EBkBqQJ45izS4lFGujEk08xLGuhp4sSUSbzEscRICakGyOdARhIE6GEPucySJpY5kQ/Cq28ur4XdfH/j1V8UVoo5X5V+B3dl2f8qvvoxd3t6GPv8HZ7dXs+98XT6uJ0Oj8GZ4c6tvV6vzV865ka375utod+9i+pX/O1Uu1tT76tT38TE+Hq+tzud6Of9Xo9T0/S/xytLm12v4NWztfhnda3lbevs7dnXsWL1vT3Kte91triqYuHW/9bf3WPnjq5r5savbHd67V8Nu6r5+lmZtrP0eO63Ba+upVuWtf7bvByg2/0w+5hz8ru14ND5ex/Odw4F7uRWrYedwU2tXmw5m1u+S7lWdjvTq5e/Kv+1apZxrdjT2dHizdHDrlrH1cvkbrWe5k97u6WRnXdviw6zkvc3cD9TOt7+7W9z2/Ys+Sx9VTPwGeYLmrz+h8fQt5u5v8/3fZ5sXKnc4MOT1+n0upicmOVDT86GfY4bPf5vN7XSxMT5Mnsdry8e84///+quHp9l19fRz8vkds+O7qb+9pWe1WvXdb7NWza3vNO3V3cZZ2rPDr1svHwO3Nq14sBuZu3P1zOvuWP++s8ex9O95e5U/vW9/F7Jtb+p+PGeRtzlg8VfG5t5TyAAAAAAAAAAAAAAAARu1PHU9QX3wAAAAAAAAAAAAAAAiiXyXwAAAAAAAAAAAAAAAiiXyXwAAAAAAAAAAAAAAAiiXyXwAAAAAAAAAAAAAAAiiXyXwAEbDTyAAAAAAAAAAAAAEctTx1PUF98AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAABHx08gAAAAAAAAAAj108dT1BffAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAgankAAAAAAAEZGnjqeoL74AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAEYinkAAAAEH08dT1BffAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAA==","endPos":1024,"fileName":"测试传输文件.rar","fileUrl":"C:\\Users\\fuzhengwei1\\Desktop\\测试传输文件.rar","status":1}2019-08-04 19:46:46 bugstack虫洞栈服务端,接收客户端传输文件数据{"beginPos":1025,"bytes":"AAI8VPIAEfZTx1PUF98AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8AAAAAAAAAAAAAAAIol8l8R+dPIAAAAAAAAAAAAAAAjt08dT1BffAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAAAAAAAAAAAAACKJfJfAAAIWp5AAAAAAAAAAAAEYGnjqeoL74AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAAAAAAAAAAAARRL5L4AAAAABGYp5AAAAAAAAAEc/Tx1PUF98AAAAAAAAIyFPIAAAAAACB6eOp6gvvgAAAAAAAAAARiKeQAAAAQfTx1PUF98AAAAAAAAAAAAAjAU8gACF6eOp6gvvgAAAAAAAAAAAAAABFH9IDEPXsAQAcA","endPos":1400,"fileName":"测试传输文件.rar","fileUrl":"C:\\Users\\fuzhengwei1\\Desktop\\测试传输文件.rar","status":2}客户端断开链接/127.0.0.1:7397Process finished with exit code -1

客户端执行结果

itstack-demo-netty client start done. {关注公众号:bugstack虫洞栈,获取源码}链接报告开始链接报告信息:本客户端链接到服务端。channelId:71399d8c链接报告IP:127.0.0.1链接报告Port:54974链接报告完毕2019-08-04 19:46:46 bugstack虫洞栈客户端传输文件信息。FILE:测试传输文件.rar SIZE(byte)10242019-08-04 19:46:46 bugstack虫洞栈客户端传输文件信息。FILE:测试传输文件.rar SIZE(byte):375Process finished with exit code -1

感谢各位的阅读,以上就是“怎么使用java Netty实现传输文件、分片发送、断点续传”的内容了,经过本文的学习后,相信大家对怎么使用java Netty实现传输文件、分片发送、断点续传这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/itstack/blog/4409785

AI

开发者交流群×