基于netty4 的文件上传

客户端:

[java]  view plain  copy
  1. public class UpLoadClient {  
  2.     private StringBuffer resultBuffer = new StringBuffer();  
  3.     private EventLoopGroup group = null;  
  4.     private HttpDataFactory factory = null;  
  5.       
  6.     private Object waitObject = new Object();  
  7.       
  8.     private ChannelFuture future = null;  
  9.       
  10.     public UpLoadClient(String host, int port) throws Exception {  
  11.         this.group = new NioEventLoopGroup();  
  12.         this.factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);  
  13.           
  14.         Bootstrap b = new Bootstrap();  
  15.         b.option(ChannelOption.TCP_NODELAY, true);  
  16.         b.option(ChannelOption.SO_SNDBUF, 1048576*200);  
  17.         b.option(ChannelOption.SO_KEEPALIVE, true);  
  18.           
  19.         b.group(group).channel(NioSocketChannel.class);  
  20.         b.handler(new UpLoadClientIntializer());  
  21.           
  22.         this.future = b.connect(host, port).sync();  
  23.     }  
  24.       
  25.     public void uploadFile(String path) {  
  26.         if(path == null) {  
  27.             System.out.println("上传文件的路径不能为null...");  
  28.             return;  
  29.         }  
  30.         File file = new File(path);  
  31.         if (!file.canRead()) {  
  32.             System.out.println(file.getName() + "不可读...");  
  33.             return;  
  34.         }  
  35.         if (file.isHidden() || !file.isFile()) {  
  36.             System.out.println(file.getName() + "不存在...");  
  37.             return;  
  38.         }  
  39.           
  40.         try {  
  41.             HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "");  
  42.               
  43.             HttpPostRequestEncoder bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false);  
  44.               
  45.             bodyRequestEncoder.addBodyAttribute("getform""POST");  
  46.             bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed"false);  
  47.               
  48.             List<InterfaceHttpData> bodylist = bodyRequestEncoder.getBodyListAttributes();  
  49.             if (bodylist == null) {  
  50.                 System.out.println("请求体不存在...");  
  51.                 return;  
  52.             }  
  53.               
  54.             HttpRequest request2 = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, file.getName());  
  55.             HttpPostRequestEncoder bodyRequestEncoder2 = new HttpPostRequestEncoder(factory, request2, true);  
  56.               
  57.             bodyRequestEncoder2.setBodyHttpDatas(bodylist);  
  58.             bodyRequestEncoder2.finalizeRequest();  
  59.               
  60.             Channel channel = this.future.channel();  
  61.             if(channel.isActive() && channel.isWritable()) {  
  62.                 channel.writeAndFlush(request2);  
  63.                   
  64.                 if (bodyRequestEncoder2.isChunked()) {  
  65.                     channel.writeAndFlush(bodyRequestEncoder2).awaitUninterruptibly();  
  66.                 }  
  67.                   
  68.                 bodyRequestEncoder2.cleanFiles();  
  69.             }  
  70.             channel.closeFuture().sync();  
  71.         } catch (Exception e) {  
  72.             e.printStackTrace();  
  73.         }  
  74.     }  
  75.       
  76.     public void shutdownClient() {  
  77.         // 等待数据的传输通道关闭  
  78.         group.shutdownGracefully();  
  79.         factory.cleanAllHttpDatas();  
  80.     }  
  81.       
  82.     public boolean isCompleted() {  
  83.         while(waitObject != null) {  
  84.             //当通道处于开通和活动时,处于等待  
  85.         }  
  86.         if(resultBuffer.length() > 0) {  
  87.             if("200".equals(resultBuffer.toString())) {  
  88.                 resultBuffer.setLength(0);  
  89.                 return true;  
  90.             }  
  91.         }  
  92.         return false;  
  93.     }  
  94.       
  95.     private class UpLoadClientIntializer extends ChannelInitializer<SocketChannel> {  
  96.         @Override  
  97.         protected void initChannel(SocketChannel ch) throws Exception {  
  98.             ChannelPipeline pipeline = ch.pipeline();  
  99.               
  100.             pipeline.addLast("decoder"new HttpResponseDecoder());  
  101.             pipeline.addLast("encoder"new HttpRequestEncoder());    
  102.             pipeline.addLast("chunkedWriter"new ChunkedWriteHandler());    
  103.   
  104.             pipeline.addLast("dispatcher"new UpLoadClientHandler());  
  105.         }  
  106.     }  
  107.       
  108.     private class UpLoadClientHandler extends SimpleChannelInboundHandler<HttpObject> {  
  109.         private boolean readingChunks = false;  
  110.         private int succCode = 200;  
  111.           
  112.         protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg)  
  113.                 throws Exception {  
  114.             if (msg instanceof HttpResponse) {  
  115.                 HttpResponse response = (HttpResponse) msg;  
  116.                   
  117.                 succCode = response.getStatus().code();  
  118.                   
  119.                 if (succCode == 200 && HttpHeaders.isTransferEncodingChunked(response)) {  
  120.                     readingChunks = true;  
  121.                 }  
  122.             }  
  123.                   
  124.             if (msg instanceof HttpContent) {  
  125.                 HttpContent chunk = (HttpContent) msg;  
  126.                 System.out.println("【响应】"+succCode+">>"+chunk.content().toString(CharsetUtil.UTF_8));  
  127.                 if (chunk instanceof LastHttpContent) {  
  128.                     readingChunks = false;  
  129.                 }  
  130.             }  
  131.               
  132.             if (!readingChunks) {  
  133.                 resultBuffer.append(succCode);  
  134.                 ctx.channel().close();  
  135.             }  
  136.         }  
  137.           
  138.         @Override  
  139.         public void channelInactive(ChannelHandlerContext ctx) throws Exception {  
  140.             waitObject = null;  
  141.         }  
  142.   
  143.         @Override  
  144.         public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)  
  145.                 throws Exception {  
  146.               
  147.             resultBuffer.setLength(0);  
  148.             resultBuffer.append(500);  
  149.             System.out.println("管道异常:" + cause.getMessage());  
  150.             cause.printStackTrace();  
  151.             ctx.channel().close();  
  152.         }  
  153.     }  
  154. }  


 

服务端:

[java]  view plain  copy
  1. public class DBServer extends Thread {  
  2.       
  3.     //单实例  
  4.     private static DBServer dbServer = null;  
  5.       
  6.     //定时调度的周期实例  
  7.     private static Scheduler sched = null;  
  8.       
  9.     private EventLoopGroup bossGroup = null;  
  10.     private EventLoopGroup workerGroup = null;  
  11.     //创建实例  
  12.     public static DBServer newBuild() {  
  13.         if(dbServer == null) {  
  14.             dbServer = new DBServer();  
  15.         }  
  16.         return dbServer;  
  17.     }  
  18.       
  19.     public void run() {  
  20.         try {             
  21.             startServer();  
  22.         } catch(Exception e) {  
  23.             System.out.println("数据服务启动出现异常:"+e.toString());  
  24.             e.printStackTrace();  
  25.         }  
  26.     }  
  27.       
  28.     private void startServer() throws Exception {  
  29.         bossGroup = new NioEventLoopGroup();  
  30.         workerGroup = new NioEventLoopGroup();  
  31.           
  32.         try {  
  33.             ServerBootstrap b = new ServerBootstrap();  
  34.               
  35.             b.group(bossGroup, workerGroup);  
  36.               
  37.             b.option(ChannelOption.TCP_NODELAY, true);  
  38.             b.option(ChannelOption.SO_TIMEOUT, 60000);  
  39.             b.option(ChannelOption.SO_SNDBUF, 1048576*200);  
  40.               
  41.             b.option(ChannelOption.SO_KEEPALIVE, true);  
  42.               
  43.             b.channel(NioServerSocketChannel.class);  
  44.             b.childHandler(new DBServerInitializer());  
  45.   
  46.             // 服务器绑定端口监听  
  47.             ChannelFuture f = b.bind(DBConfig.curHost.getIp(), DBConfig.curHost.getPort()).sync();  
  48.               
  49.             System.out.println("数据服务:"+DBConfig.curHost.getServerHost()+"启动完成...");  
  50.             // 监听服务器关闭监听  
  51.             f.channel().closeFuture().sync();  
  52.         } finally {  
  53.             bossGroup.shutdownGracefully();  
  54.             workerGroup.shutdownGracefully();  
  55.         }  
  56.     }  
  57. }  
[java]  view plain  copy
  1. public class DBServerHandler extends SimpleChannelInboundHandler<HttpObject> {  
  2.       
  3.     private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);  
  4.       
  5.     private String uri = null;  
  6.       
  7.     private HttpRequest request = null;  
  8.       
  9.     private HttpPostRequestDecoder decoder;  
  10.       
  11.     //message、download、upload  
  12.     private String type = "message";  
  13.       
  14.     public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";  
  15.     public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";  
  16.     public static final int HTTP_CACHE_SECONDS = 60;  
  17.       
  18.     static {  
  19.         DiskFileUpload.baseDirectory = DBConfig.curHost.getZipPath();  
  20.     }  
  21.   
  22.     @Override  
  23.     public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {  
  24.         if (msg instanceof HttpRequest) {  
  25.             request = (HttpRequest) msg;  
  26.               
  27.             uri = sanitizeUri(request.getUri());  
  28.               
  29.             if (request.getMethod() == HttpMethod.POST) {  
  30.                 if (decoder != null) {  
  31.                     decoder.cleanFiles();  
  32.                     decoder = null;  
  33.                 }  
  34.                 try {  
  35.                   decoder = new HttpPostRequestDecoder(factory, request);  
  36.                 } catch (Exception e) {  
  37.                     e.printStackTrace();  
  38.                     writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, e.toString());  
  39.                     ctx.channel().close();  
  40.                     return;  
  41.                 }  
  42.             }  
  43.         }  
  44.           
  45.         if (decoder != null && msg instanceof HttpContent) {  
  46.             HttpContent chunk = (HttpContent) msg;  
  47.               
  48.             try {  
  49.                 decoder.offer(chunk);  
  50.             } catch (Exception e) {  
  51.                 e.printStackTrace();  
  52.                 writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, e.toString());  
  53.                 ctx.channel().close();  
  54.                 return;  
  55.             }  
  56.               
  57.             readHttpDataChunkByChunk();  
  58.               
  59.             if (chunk instanceof LastHttpContent) {  
  60.                 writeResponse(ctx.channel(), HttpResponseStatus.OK, "");  
  61.                 reset();  
  62.                 return;  
  63.             }  
  64.         }  
  65.     }  
  66.   
  67.     private String sanitizeUri(String uri) {  
  68.         try {  
  69.             uri = URLDecoder.decode(uri, "UTF-8");  
  70.         } catch(UnsupportedEncodingException e) {  
  71.             try {  
  72.                 uri = URLDecoder.decode(uri, "ISO-8859-1");  
  73.             } catch(UnsupportedEncodingException e1) {  
  74.                 throw new Error();  
  75.             }  
  76.         }  
  77.   
  78.         return uri;  
  79.     }  
  80.   
  81.     private void reset() {  
  82.         request = null;  
  83.   
  84.         //销毁decoder释放所有的资源  
  85.         decoder.destroy();  
  86.           
  87.         decoder = null;  
  88.     }  
  89.   
  90.     /** 
  91.      * 通过chunk读取request,获取chunk数据 
  92.      * @throws IOException  
  93.      */  
  94.     private void readHttpDataChunkByChunk() throws IOException {  
  95.         try {  
  96.             while (decoder.hasNext()) {  
  97.                   
  98.                 InterfaceHttpData data = decoder.next();  
  99.                 if (data != null) {  
  100.                     try {  
  101.                         writeHttpData(data);  
  102.                     } finally {  
  103.                         data.release();  
  104.                     }  
  105.                 }  
  106.             }  
  107.         } catch (EndOfDataDecoderException e1) {  
  108.             System.out.println("end chunk");  
  109.         }  
  110.     }  
  111.   
  112.     private void writeHttpData(InterfaceHttpData data) throws IOException {  
  113.         if (data.getHttpDataType() == HttpDataType.FileUpload) {  
  114.             FileUpload fileUpload = (FileUpload) data;  
  115.             if (fileUpload.isCompleted()) {  
  116.                   
  117.                 StringBuffer fileNameBuf = new StringBuffer();  
  118.                 fileNameBuf.append(DiskFileUpload.baseDirectory)  
  119.                            .append(uri);  
  120.   
  121.                 fileUpload.renameTo(new File(fileNameBuf.toString()));  
  122.             }  
  123.         } else if (data.getHttpDataType() == HttpDataType.Attribute) {  
  124.             Attribute attribute = (Attribute) data;  
  125.             if(CommonParam.DOWNLOAD_COLLECTION.equals(attribute.getName())) {  
  126.                 SynchMessageWatcher.newBuild().getMsgQueue().add(attribute.getValue());  
  127.             }  
  128.         }  
  129.     }  
  130.       
  131.     private void writeDownLoadResponse(ChannelHandlerContext ctx, RandomAccessFile raf, File file) throws Exception {  
  132.         long fileLength = raf.length();  
  133.           
  134.         //判断是否关闭请求响应连接  
  135.         boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION))  
  136.                 || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0)  
  137.                 && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION));  
  138.           
  139.         HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);  
  140.         HttpHeaders.setContentLength(response, fileLength);  
  141.           
  142.         setContentHeader(response, file);  
  143.           
  144.         if (!close) {  
  145.             response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);  
  146.         }  
  147.           
  148.         ctx.write(response);  
  149.         System.out.println("读取大小:"+fileLength);  
  150.           
  151.         final FileRegion region = new DefaultFileRegion(raf.getChannel(), 01000);  
  152.         ChannelFuture writeFuture = ctx.write(region, ctx.newProgressivePromise());  
  153.         writeFuture.addListener(new ChannelProgressiveFutureListener() {  
  154.             public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {  
  155.                 if (total < 0) {  
  156.                     System.err.println(future.channel() + " Transfer progress: " + progress);  
  157.                 } else {  
  158.                     System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total);  
  159.                 }  
  160.             }  
  161.   
  162.             public void operationComplete(ChannelProgressiveFuture future) {  
  163.             }  
  164.         });  
  165.           
  166.         ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);  
  167.         if(close) {  
  168.             raf.close();  
  169.             lastContentFuture.addListener(ChannelFutureListener.CLOSE);  
  170.         }  
  171.     }  
  172.       
  173.     private static void setContentHeader(HttpResponse response, File file) {  
  174.         MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();  
  175.         response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));  
  176.           
  177.         SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);  
  178.         dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));  
  179.   
  180.         // Date header  
  181.         Calendar time = new GregorianCalendar();  
  182.         response.headers().set(DATE, dateFormatter.format(time.getTime()));  
  183.   
  184.         // Add cache headers  
  185.         time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);  
  186.         response.headers().set(EXPIRES, dateFormatter.format(time.getTime()));  
  187.         response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);  
  188.         response.headers().set(LAST_MODIFIED, dateFormatter.format(new Date(file.lastModified())));  
  189.     }  
  190.       
  191.     private void writeResponse(Channel channel, HttpResponseStatus httpResponseStatus, String returnMsg) {  
  192.         String resultStr = "节点【"+DBConfig.curHost.getServerHost()+"】";  
  193.         if(httpResponseStatus.code() == HttpResponseStatus.OK.code()) {  
  194.             resultStr += "正常接收";  
  195.             if("message".equals(type)) {  
  196.                 resultStr += "字符串。";  
  197.             } else if("upload".equals(type)) {  
  198.                 resultStr += "上传文件。";  
  199.             } else if("download".equals(type)) {  
  200.                 resultStr += "下载文件名。";  
  201.             }  
  202.         } else if(httpResponseStatus.code() == HttpResponseStatus.INTERNAL_SERVER_ERROR.code()) {  
  203.             resultStr += "接收";  
  204.             if("message".equals(type)) {  
  205.                 resultStr += "字符串";  
  206.             } else if("upload".equals(type)) {  
  207.                 resultStr += "上传文件";  
  208.             } else if("download".equals(type)) {  
  209.                 resultStr += "下载文件名";  
  210.             }  
  211.             resultStr += "的过程中出现异常:"+returnMsg;  
  212.         }  
  213.         //将请求响应的内容转换成ChannelBuffer.  
  214.         ByteBuf buf = copiedBuffer(resultStr, CharsetUtil.UTF_8);  
  215.   
  216.         //判断是否关闭请求响应连接  
  217.         boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION))  
  218.                 || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0)  
  219.                 && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION));  
  220.           
  221.         //构建请求响应对象  
  222.         FullHttpResponse response = new DefaultFullHttpResponse(  
  223.                 HttpVersion.HTTP_1_1, httpResponseStatus, buf);  
  224.         response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");  
  225.   
  226.         if (!close) {  
  227.             //若该请求响应是最后的响应,则在响应头中没有必要添加'Content-Length'  
  228.             response.headers().set(CONTENT_LENGTH, buf.readableBytes());  
  229.         }  
  230.           
  231.         //发送请求响应  
  232.         ChannelFuture future = channel.writeAndFlush(response);  
  233.         //发送请求响应操作结束后关闭连接  
  234.         if (close) {  
  235.             future.addListener(ChannelFutureListener.CLOSE);  
  236.         }  
  237.     }  
  238.   
  239.     @Override  
  240.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
  241.         cause.getCause().printStackTrace();  
  242.         writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, "数据文件通过过程中出现异常:"+cause.getMessage().toString());  
  243.         ctx.channel().close();  
  244.     }  
  245. }  
[java]  view plain  copy
  1. public class DBServerInitializer extends ChannelInitializer<SocketChannel> {  
  2.   
  3.     @Override  
  4.     public void initChannel(SocketChannel ch) {  
  5.         ChannelPipeline pipeline = ch.pipeline();  
  6.           
  7.         pipeline.addLast("decoder"new HttpRequestDecoder());  
  8.         pipeline.addLast("encoder"new HttpResponseEncoder());  
  9.           
  10.         pipeline.addLast("deflater"new HttpContentCompressor());  
  11.   
  12.         pipeline.addLast("handler"new DBServerHandler());  
  13.     }  
  14. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值