一:简介
netty传输文件的例子并不多,当前的项目刚才需要使用netty,所以就记录一下使用方法,使用netty传输文件,首先需要启动一个服务端,等待服务端请求监听,然后传输文件的时候,启动一个客户端线程来传输文件。
二:启动一个服务端等待监听
1):引入netty版本号
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.15.Final</version> </dependency>
2):启动一个服务端
//声明两个多线程事件循环器 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); //声明nio服务启动类 ServerBootstrap serverBootstrap = new ServerBootstrap (); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) throws Exception { System.out.println("有客户端连接上来:"+ch.localAddress().toString()); ch.pipeline().addLast(new ObjectEncoder()); ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度 ch.pipeline().addLast(new FileUploadServerHandler()); } }); ChannelFuture f = b.bind(port).sync();//邦定端口并启动 System.out.println("file server 等待连接:"); f.channel().closeFuture().sync();
3):接收文件的handler extends ChannelInboundHandlerAdapter,在channelRead方法中获取文件
//自定义的一个对像,保存文件相关的属性 FileUploadFile ef = (FileUploadFile) msg; byte[] bytes = ef.getBytes(); byteRead = ef.getEndPos(); String md5 = ef.getFile_md5();//文件名 //读文件的相关代码 String path = file_dir + File.separator + md5; File file = new File(path); RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); randomAccessFile.seek(start); randomAccessFile.write(bytes); start = start + byteRead; System.out.println("path:"+path+","+byteRead); if (byteRead > 0) { ctx.writeAndFlush(start); randomAccessFile.close(); if(byteRead!=1024 * 10){//测试每次读取10k,当文件大小不是10k时,默认文件读完, 这里可以不用调用channelInactive() Thread.sleep(1000); channelInactive(ctx); } } else { //System.out.println("文件接收完成"); //ctx.flush(); ctx.close(); } }
服务端的代码大致就是这些,我们来看客户端的代码。
4:) 初始化客户端
//客户端只创建一个事件循环处理器 EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap();
//注意这里和服务端的区别,服务端:NioServerSocketChannel,客户端:NioSocketChannel
b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new ObjectEncoder());
ch.pipeline() .addLast(
new ObjectDecoder( ClassResolvers .weakCachingConcurrentResolver(null)));
ch.pipeline() .addLast( new FileUploadClientHandler( fileUploadFile)); } });
ChannelFuture f = b.connect(host, port).sync(); //连接服务端
f.channel().closeFuture().sync();//关闭
5:)上传文件的handler同样继承为 ChannelInboundHandlerAdapter
在channelInactive方法将文件相关信息,如:文件名,文件长度等封装一个对像,输出至服务端
FileUploadFile uploadFile = new FileUploadFile(); File file = new File("d:/source.rar"); String fileMd5 = file.getName();// 文件名 uploadFile.setFile(file); uploadFile.setFile_md5(fileMd5);
在channelRead方法来读取和上传文件流
randomAccessFile = new RandomAccessFile( fileUploadFile.getFile(), "r"); randomAccessFile.seek(start); fileUploadFile.setEndPos(byteRead); fileUploadFile.setBytes(bytes); try { ctx.writeAndFlush(fileUploadFile); } catch (Exception e) { e.printStackTrace(); }
主要的代码就是这些,demo下载地址:github