一:簡介
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