【初学与研发之NETTY】netty4之文件上传
来源:互联网 发布:软件系统结构是什么 编辑:程序博客网 时间:2024/04/29 08:31
客户端:
public class UpLoadClient {private StringBuffer resultBuffer = new StringBuffer();private EventLoopGroup group = null;private HttpDataFactory factory = null;private Object waitObject = new Object();private ChannelFuture future = null;public UpLoadClient(String host, int port) throws Exception {this.group = new NioEventLoopGroup();this.factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); Bootstrap b = new Bootstrap(); b.option(ChannelOption.TCP_NODELAY, true); b.option(ChannelOption.SO_SNDBUF, 1048576*200); b.option(ChannelOption.SO_KEEPALIVE, true); b.group(group).channel(NioSocketChannel.class); b.handler(new UpLoadClientIntializer()); this.future = b.connect(host, port).sync();}public void uploadFile(String path) {if(path == null) {System.out.println("上传文件的路径不能为null..."); return;}File file = new File(path);if (!file.canRead()) {System.out.println(file.getName() + "不可读..."); return;}if (file.isHidden() || !file.isFile()) { System.out.println(file.getName() + "不存在..."); return; } try { HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, ""); HttpPostRequestEncoder bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false); bodyRequestEncoder.addBodyAttribute("getform", "POST"); bodyRequestEncoder.addBodyFileUpload("myfile", file, "application/x-zip-compressed", false); List<InterfaceHttpData> bodylist = bodyRequestEncoder.getBodyListAttributes(); if (bodylist == null) { System.out.println("请求体不存在...");return;} HttpRequest request2 = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, file.getName()); HttpPostRequestEncoder bodyRequestEncoder2 = new HttpPostRequestEncoder(factory, request2, true); bodyRequestEncoder2.setBodyHttpDatas(bodylist); bodyRequestEncoder2.finalizeRequest(); Channel channel = this.future.channel(); if(channel.isActive() && channel.isWritable()) { channel.writeAndFlush(request2); if (bodyRequestEncoder2.isChunked()) { channel.writeAndFlush(bodyRequestEncoder2).awaitUninterruptibly(); } bodyRequestEncoder2.cleanFiles(); } channel.closeFuture().sync();} catch (Exception e) {e.printStackTrace();}}public void shutdownClient() {// 等待数据的传输通道关闭group.shutdownGracefully();factory.cleanAllHttpDatas();}public boolean isCompleted() {while(waitObject != null) {//当通道处于开通和活动时,处于等待}if(resultBuffer.length() > 0) {if("200".equals(resultBuffer.toString())) {resultBuffer.setLength(0);return true;}}return false;}private class UpLoadClientIntializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("decoder", new HttpResponseDecoder());pipeline.addLast("encoder", new HttpRequestEncoder()); pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); pipeline.addLast("dispatcher", new UpLoadClientHandler());}}private class UpLoadClientHandler extends SimpleChannelInboundHandler<HttpObject> {private boolean readingChunks = false;private int succCode = 200;protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg)throws Exception {if (msg instanceof HttpResponse) {HttpResponse response = (HttpResponse) msg;succCode = response.getStatus().code(); if (succCode == 200 && HttpHeaders.isTransferEncodingChunked(response)) { readingChunks = true; }}if (msg instanceof HttpContent) { HttpContent chunk = (HttpContent) msg; System.out.println("【响应】"+succCode+">>"+chunk.content().toString(CharsetUtil.UTF_8)); if (chunk instanceof LastHttpContent) { readingChunks = false; } }if (!readingChunks) {resultBuffer.append(succCode);ctx.channel().close();}}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {waitObject = null;}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)throws Exception {resultBuffer.setLength(0);resultBuffer.append(500);System.out.println("管道异常:" + cause.getMessage());cause.printStackTrace(); ctx.channel().close();}}}
服务端:
public class DBServer extends Thread {//单实例private static DBServer dbServer = null;//定时调度的周期实例private static Scheduler sched = null;private EventLoopGroup bossGroup = null; private EventLoopGroup workerGroup = null;//创建实例public static DBServer newBuild() {if(dbServer == null) {dbServer = new DBServer();}return dbServer;}public void run() {try {startServer();} catch(Exception e) {System.out.println("数据服务启动出现异常:"+e.toString());e.printStackTrace();}}private void startServer() throws Exception {bossGroup = new NioEventLoopGroup(); workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup); b.option(ChannelOption.TCP_NODELAY, true);b.option(ChannelOption.SO_TIMEOUT, 60000); b.option(ChannelOption.SO_SNDBUF, 1048576*200); b.option(ChannelOption.SO_KEEPALIVE, true); b.channel(NioServerSocketChannel.class); b.childHandler(new DBServerInitializer()); // 服务器绑定端口监听 ChannelFuture f = b.bind(DBConfig.curHost.getIp(), DBConfig.curHost.getPort()).sync(); System.out.println("数据服务:"+DBConfig.curHost.getServerHost()+"启动完成..."); // 监听服务器关闭监听 f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); }}}
public class DBServerHandler extends SimpleChannelInboundHandler<HttpObject> {private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);private String uri = null;private HttpRequest request = null;private HttpPostRequestDecoder decoder;//message、download、uploadprivate String type = "message";public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; public static final String HTTP_DATE_GMT_TIMEZONE = "GMT"; public static final int HTTP_CACHE_SECONDS = 60; static { DiskFileUpload.baseDirectory = DBConfig.curHost.getZipPath(); } @Override public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if (msg instanceof HttpRequest) { request = (HttpRequest) msg; uri = sanitizeUri(request.getUri()); if (request.getMethod() == HttpMethod.POST) { if (decoder != null) {decoder.cleanFiles();decoder = null;} try { decoder = new HttpPostRequestDecoder(factory, request); } catch (Exception e) { e.printStackTrace(); writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, e.toString()); ctx.channel().close(); return; } } } if (decoder != null && msg instanceof HttpContent) { HttpContent chunk = (HttpContent) msg; try { decoder.offer(chunk); } catch (Exception e) { e.printStackTrace(); writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, e.toString()); ctx.channel().close(); return; } readHttpDataChunkByChunk(); if (chunk instanceof LastHttpContent) { writeResponse(ctx.channel(), HttpResponseStatus.OK, ""); reset(); return; } } }private String sanitizeUri(String uri) {try {uri = URLDecoder.decode(uri, "UTF-8");} catch(UnsupportedEncodingException e) {try {uri = URLDecoder.decode(uri, "ISO-8859-1");} catch(UnsupportedEncodingException e1) {throw new Error();}}return uri;} private void reset() { request = null; //销毁decoder释放所有的资源 decoder.destroy(); decoder = null; } /** * 通过chunk读取request,获取chunk数据 * @throws IOException */ private void readHttpDataChunkByChunk() throws IOException { try { while (decoder.hasNext()) { InterfaceHttpData data = decoder.next(); if (data != null) { try { writeHttpData(data); } finally { data.release(); } } } } catch (EndOfDataDecoderException e1) { System.out.println("end chunk"); } } private void writeHttpData(InterfaceHttpData data) throws IOException { if (data.getHttpDataType() == HttpDataType.FileUpload) { FileUpload fileUpload = (FileUpload) data; if (fileUpload.isCompleted()) { StringBuffer fileNameBuf = new StringBuffer();fileNameBuf.append(DiskFileUpload.baseDirectory) .append(uri);fileUpload.renameTo(new File(fileNameBuf.toString())); } } else if (data.getHttpDataType() == HttpDataType.Attribute) { Attribute attribute = (Attribute) data; if(CommonParam.DOWNLOAD_COLLECTION.equals(attribute.getName())) { SynchMessageWatcher.newBuild().getMsgQueue().add(attribute.getValue()); } } } private void writeDownLoadResponse(ChannelHandlerContext ctx, RandomAccessFile raf, File file) throws Exception { long fileLength = raf.length(); //判断是否关闭请求响应连接 boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION)) || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION)); HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); HttpHeaders.setContentLength(response, fileLength); setContentHeader(response, file); if (!close) { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } ctx.write(response); System.out.println("读取大小:"+fileLength); final FileRegion region = new DefaultFileRegion(raf.getChannel(), 0, 1000);ChannelFuture writeFuture = ctx.write(region, ctx.newProgressivePromise());writeFuture.addListener(new ChannelProgressiveFutureListener() { public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { System.err.println(future.channel() + " Transfer progress: " + progress); } else { System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total); } } public void operationComplete(ChannelProgressiveFuture future) { } }); ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); if(close) { raf.close(); lastContentFuture.addListener(ChannelFutureListener.CLOSE); }} private static void setContentHeader(HttpResponse response, File file) { MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath())); SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE)); // Date header Calendar time = new GregorianCalendar(); response.headers().set(DATE, dateFormatter.format(time.getTime())); // Add cache headers time.add(Calendar.SECOND, HTTP_CACHE_SECONDS); response.headers().set(EXPIRES, dateFormatter.format(time.getTime())); response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS); response.headers().set(LAST_MODIFIED, dateFormatter.format(new Date(file.lastModified()))); } private void writeResponse(Channel channel, HttpResponseStatus httpResponseStatus, String returnMsg) { String resultStr = "节点【"+DBConfig.curHost.getServerHost()+"】"; if(httpResponseStatus.code() == HttpResponseStatus.OK.code()) { resultStr += "正常接收"; if("message".equals(type)) { resultStr += "字符串。"; } else if("upload".equals(type)) { resultStr += "上传文件。"; } else if("download".equals(type)) { resultStr += "下载文件名。"; } } else if(httpResponseStatus.code() == HttpResponseStatus.INTERNAL_SERVER_ERROR.code()) { resultStr += "接收"; if("message".equals(type)) { resultStr += "字符串"; } else if("upload".equals(type)) { resultStr += "上传文件"; } else if("download".equals(type)) { resultStr += "下载文件名"; } resultStr += "的过程中出现异常:"+returnMsg; } //将请求响应的内容转换成ChannelBuffer. ByteBuf buf = copiedBuffer(resultStr, CharsetUtil.UTF_8); //判断是否关闭请求响应连接 boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION)) || request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) && !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION)); //构建请求响应对象 FullHttpResponse response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, httpResponseStatus, buf); response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); if (!close) { //若该请求响应是最后的响应,则在响应头中没有必要添加'Content-Length' response.headers().set(CONTENT_LENGTH, buf.readableBytes()); } //发送请求响应 ChannelFuture future = channel.writeAndFlush(response); //发送请求响应操作结束后关闭连接 if (close) { future.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.getCause().printStackTrace(); writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, "数据文件通过过程中出现异常:"+cause.getMessage().toString()); ctx.channel().close(); }}
public class DBServerInitializer extends ChannelInitializer<SocketChannel> { @Override public void initChannel(SocketChannel ch) { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("decoder", new HttpRequestDecoder());pipeline.addLast("encoder", new HttpResponseEncoder());pipeline.addLast("deflater", new HttpContentCompressor()); pipeline.addLast("handler", new DBServerHandler()); }}
2 0
- 【初学与研发之NETTY】netty4之文件上传
- 【初学与研发之NETTY】netty4之文件下载
- 【初学与研发之NETTY】netty4之对象、字节传输
- 【初学与研发之NETTY】netty3之文件上传
- 【初学与研发之NETTY】netty3之文件下载
- 【初学与研发之NETTY】简介与HelloWorld之例(netty3)
- 【初学与研发之NETTY】netty3之传送字符串以及超长字符串的问题
- 【Netty4.x】Netty源码分析(三)之LineBasedFrameDecoder
- 【Netty4.X】Netty源码分析之NioEventLoopGroup(五)
- 【Netty4.X】Netty源码分析之NioEventLoop(六)
- 【Netty4.X】Netty源码分析之ByteBuf(七)
- Netty4 学习笔记之四: Netty HTTP服务的实现
- netty与rabbitmq整合之netty传输大文件解决
- 文件上传与下载之文件下载
- 【Netty4 简单项目实践】五、Netty4接收HTTP文件上传
- netty之Channel与Pipeline
- Netty4 学习笔记之二:客户端与服务端心跳 demo
- 初学Java NIO框架Netty(一) 之 Hello
- java多线程笔记
- web bench源码学习2
- web bench源码学习3
- 先从从从消息再次的上
- 我们不是不想高飞
- 【初学与研发之NETTY】netty4之文件上传
- tinyhttpd源码学习1
- 【初学与研发之NETTY】netty4之对象、字节传输
- 实打实的健康路服饰的
- tinyhttpd源码学习2
- RMI远程文件上传实现
- java调用linux命令传输远程大文件
- hogan outlet major clothing city has a similar situation.
- 字符串解压缩类库(zip、GZIP、QuickLz、snappy、lzf、jzlib)介绍