Author: rickiyang
source: www.cnblogs.com/rickiyang/p/11074222.html
Today, let's complete a task of file transfer using netty. In actual projects, file transfer usually adopts FTP or HTTP attachment. In fact, there are certain application scenarios for file transmission through TCP Socket+File. Although it is not the mainstream, it is important to master this file transmission method, especially for the mutual exchange of persistent data between two cross host JVM processes.
Using netty for file transfer also takes advantage of netty's natural advantage: zero copy function. Many students have heard of the "zero copy" function of netty, but they don't know where it is. Let's briefly introduce it below:
Netty's "zero copy" is mainly reflected in the following three aspects:
1) Netty's receive and send ByteBuffer adopts DIRECT BUFFERS and uses direct memory outside the heap for Socket reading and writing, without secondary copy of byte Buffer. If the traditional HEAP BUFFERS are used for Socket reading and writing, the JVM will copy a copy of the heap Buffer into the direct memory and then write it into the Socket. Compared with the direct memory outside the heap, the message is sent with one more memory copy of the Buffer.
2) Netty provides a combined Buffer object, which can aggregate multiple ByteBuffer objects. Users can operate the combined Buffer as easily as one Buffer, avoiding the traditional method of merging several small buffers into one large Buffer through memory copy.
3) Netty's file transfer adopts the transferTo method, which can directly send the data of the file buffer to the target Channel, avoiding the memory copy problem caused by the traditional circular write method.
The specific analysis will not be introduced here. If you are interested, you can refer to the relevant documents. We still focus on file transfer. As a high-performance server-side asynchronous IO framework, netty is inevitably inseparable from the file reading and writing function. We can use netty to simulate http and upload files to the server through the web page. Of course, if you want to use http, you don't need netty! put fine timber to petty use.
If you want to upload files using http in netty4, you have to use a third-party jar package: okhttp. Use this jar to send the http request. But it has been written for us in netty5. We can call the API of netty5 directly. So there is a big difference between netty4 and 5. As for which one to use, it depends on which one your company chooses! In this paper, netty4 is used to upload files. Here's our code:
pom file:
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.5.Final</version> </dependency>
server side:
import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; public class FileUploadServer { public void bind(int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = 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 { ch.pipeline().addLast(new ObjectEncoder()); ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // Maximum length ch.pipeline().addLast(new FileUploadServerHandler()); } }); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) { int port = 8080; if (args != null && args.length > 0) { try { port = Integer.valueOf(args[0]); } catch (NumberFormatException e) { e.printStackTrace(); } } try { new FileUploadServer().bind(port); } catch (Exception e) { e.printStackTrace(); } } }
server side handler:
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import java.io.File; import java.io.RandomAccessFile; public class FileUploadServerHandler extends ChannelInboundHandlerAdapter { private int byteRead; private volatile int start = 0; private String file_dir = "D:"; @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FileUploadFile) { FileUploadFile ef = (FileUploadFile) msg; byte[] bytes = ef.getBytes(); byteRead = ef.getEndPos(); String md5 = ef.getFile_md5();//file name 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; if (byteRead > 0) { ctx.writeAndFlush(start); } else { randomAccessFile.close(); ctx.close(); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } }
client side:
import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; import java.io.File; public class FileUploadClient { public void connect(int port, String host, final FileUploadFile fileUploadFile) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); 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(); } finally { group.shutdownGracefully(); } } public static void main(String[] args) { int port = 8080; if (args != null && args.length > 0) { try { port = Integer.valueOf(args[0]); } catch (NumberFormatException e) { e.printStackTrace(); } } try { FileUploadFile uploadFile = new FileUploadFile(); File file = new File("c:/1.txt"); String fileMd5 = file.getName();// file name uploadFile.setFile(file); uploadFile.setFile_md5(fileMd5); uploadFile.setStarPos(0);// File start location new FileUploadClient().connect(port, "127.0.0.1", uploadFile); } catch (Exception e) { e.printStackTrace(); } } }
client side handler:
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; public class FileUploadClientHandler extends ChannelInboundHandlerAdapter { private int byteRead; private volatile int start = 0; private volatile int lastLength = 0; public RandomAccessFile randomAccessFile; private FileUploadFile fileUploadFile; public FileUploadClientHandler(FileUploadFile ef) { if (ef.getFile().exists()) { if (!ef.getFile().isFile()) { System.out.println("Not a file :" + ef.getFile()); return; } } this.fileUploadFile = ef; } public void channelActive(ChannelHandlerContext ctx) { try { randomAccessFile = new RandomAccessFile(fileUploadFile.getFile(), "r"); randomAccessFile.seek(fileUploadFile.getStarPos()); lastLength = (int) randomAccessFile.length() / 10; byte[] bytes = new byte[lastLength]; if ((byteRead = randomAccessFile.read(bytes)) != -1) { fileUploadFile.setEndPos(byteRead); fileUploadFile.setBytes(bytes); ctx.writeAndFlush(fileUploadFile); } else { System.out.println("The file has been read"); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException i) { i.printStackTrace(); } } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof Integer) { start = (Integer) msg; if (start != -1) { randomAccessFile = new RandomAccessFile(fileUploadFile.getFile(), "r"); randomAccessFile.seek(start); System.out.println("Block length:" + (randomAccessFile.length() / 10)); System.out.println("Length:" + (randomAccessFile.length() - start)); int a = (int) (randomAccessFile.length() - start); int b = (int) (randomAccessFile.length() / 10); if (a < b) { lastLength = a; } byte[] bytes = new byte[lastLength]; System.out.println("-----------------------------" + bytes.length); if ((byteRead = randomAccessFile.read(bytes)) != -1 && (randomAccessFile.length() - start) > 0) { System.out.println("byte Length:" + bytes.length); fileUploadFile.setEndPos(byteRead); fileUploadFile.setBytes(bytes); try { ctx.writeAndFlush(fileUploadFile); } catch (Exception e) { e.printStackTrace(); } } else { randomAccessFile.close(); ctx.close(); System.out.println("The file has been read--------" + byteRead); } } } } // @Override // public void channelRead(ChannelHandlerContext ctx, Object msg) throws // Exception { // System.out.println("Server is speek : "+msg.toString()); // FileRegion filer = (FileRegion) msg; // String path = "E://Apk//APKMD5.txt"; // File fl = new File(path); // fl.createNewFile(); // RandomAccessFile rdafile = new RandomAccessFile(path, "rw"); // FileRegion f = new DefaultFileRegion(rdafile.getChannel(), 0, // rdafile.length()); // // System.out.println("This is" + ++counter + "times receive server:[" // + msg + "]"); // } // @Override // public void channelReadComplete(ChannelHandlerContext ctx) throws // Exception { // ctx.flush(); // } public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } // @Override // protected void channelRead0(ChannelHandlerContext ctx, String msg) // throws Exception { // String a = msg; // System.out.println("This is"+ // ++counter+"times receive server:["+msg+"]"); // } }
We also customize an object to count the file upload progress:
import java.io.File; import java.io.Serializable; public class FileUploadFile implements Serializable { private static final long serialVersionUID = 1L; private File file;// file private String file_md5;// file name private int starPos;// Start position private byte[] bytes;// File byte array private int endPos;// End position public int getStarPos() { return starPos; } public void setStarPos(int starPos) { this.starPos = starPos; } public int getEndPos() { return endPos; } public void setEndPos(int endPos) { this.endPos = endPos; } public byte[] getBytes() { return bytes; } public void setBytes(byte[] bytes) { this.bytes = bytes; } public File getFile() { return file; } public void setFile(File file) { this.file = file; } public String getFile_md5() { return file_md5; } public void setFile_md5(String file_md5) { this.file_md5 = file_md5; } }
Output is:
Block length: 894 Length: 8052 -----------------------------894 byte Length: 894 Block length: 894 Length: 7158 -----------------------------894 byte Length: 894 Block length: 894 Length: 6264 -----------------------------894 byte Length: 894 Block length: 894 Length: 5370 -----------------------------894 byte Length: 894 Block length: 894 Length: 4476 -----------------------------894 byte Length: 894 Block length: 894 Length: 3582 -----------------------------894 byte Length: 894 Block length: 894 Length: 2688 -----------------------------894 byte Length: 894 Block length: 894 Length: 1794 -----------------------------894 byte Length: 894 Block length: 894 Length: 900 -----------------------------894 byte Length: 894 Block length: 894 Length: 6 -----------------------------6 byte Length: 6 Block length: 894 Length: 0 -----------------------------0 The file has been read--------0 Process finished with exit code 0
This enables the upload of server-side files. Of course, we can also use http.
server side:
import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; public class HttpFileServer implements Runnable { private int port; public HttpFileServer(int port) { super(); this.port = port; } @Override public void run() { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup); serverBootstrap.channel(NioServerSocketChannel.class); //serverBootstrap.handler(new LoggingHandler(LogLevel.INFO)); serverBootstrap.childHandler(new HttpChannelInitlalizer()); try { ChannelFuture f = serverBootstrap.bind(port).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) { HttpFileServer b = new HttpFileServer(9003); new Thread(b).start(); } }
Server side initializer:
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.stream.ChunkedWriteHandler; public class HttpChannelInitlalizer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new HttpObjectAggregator(65536)); pipeline.addLast(new ChunkedWriteHandler()); pipeline.addLast(new HttpChannelHandler()); } }
server hadler:
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN; import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR; import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelProgressiveFuture; import io.netty.channel.ChannelProgressiveFutureListener; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.DefaultHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpChunkedInput; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.stream.ChunkedFile; import io.netty.util.CharsetUtil; import io.netty.util.internal.SystemPropertyUtil; import java.io.File; import java.io.FileNotFoundException; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.regex.Pattern; import javax.activation.MimetypesFileTypeMap; public class HttpChannelHandler extends SimpleChannelInboundHandler<FullHttpRequest> { 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; @Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { // Monitor decoding if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST); return; } final String uri = request.getUri(); final String path = sanitizeUri(uri); System.out.println("get file: "+path); if (path == null) { sendError(ctx, FORBIDDEN); return; } //Read the file to download File file = new File(path); if (file.isHidden() || !file.exists()) { sendError(ctx, NOT_FOUND); return; } if (!file.isFile()) { sendError(ctx, FORBIDDEN); return; } RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException ignore) { sendError(ctx, NOT_FOUND); return; } long fileLength = raf.length(); HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); HttpHeaders.setContentLength(response, fileLength); setContentTypeHeader(response, file); //setDateAndCacheHeaders(response, file); if (HttpHeaders.isKeepAlive(request)) { response.headers().set("CONNECTION", HttpHeaders.Values.KEEP_ALIVE); } // Write the initial line and the header. ctx.write(response); // Write the content. ChannelFuture sendFileFuture = ctx.write(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise()); //sendFuture is used to monitor the status of sending data sendFileFuture.addListener(new ChannelProgressiveFutureListener() { @Override public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown System.err.println(future.channel() + " Transfer progress: " + progress); } else { System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total); } } @Override public void operationComplete(ChannelProgressiveFuture future) { System.err.println(future.channel() + " Transfer complete."); } }); // Write the end marker ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); // Decide whether to close the connection or not. if (!HttpHeaders.isKeepAlive(request)) { // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); if (ctx.channel().isActive()) { sendError(ctx, INTERNAL_SERVER_ERROR); } ctx.close(); } private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*"); private static String sanitizeUri(String uri) { // Decode the path. try { uri = URLDecoder.decode(uri, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new Error(e); } if (!uri.startsWith("/")) { return null; } // Convert file separators. uri = uri.replace('/', File.separatorChar); // Simplistic dumb security check. // You will have to do something serious in the production environment. if (uri.contains(File.separator + '.') || uri.contains('.' + File.separator) || uri.startsWith(".") || uri.endsWith(".") || INSECURE_URI.matcher(uri).matches()) { return null; } // Convert to absolute path. return SystemPropertyUtil.get("user.dir") + File.separator + uri; } private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status + "\r\n", CharsetUtil.UTF_8)); response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); // Close the connection as soon as the error message is sent. ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } /** * Sets the content type header for the HTTP Response * * @param response * HTTP response * @param file * file to extract content type */ private static void setContentTypeHeader(HttpResponse response, File file) { MimetypesFileTypeMap m = new MimetypesFileTypeMap(); String contentType = m.getContentType(file.getPath()); if (!contentType.equals("application/octet-stream")) { contentType += "; charset=utf-8"; } response.headers().set(CONTENT_TYPE, contentType); } }
client side:
import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.stream.ChunkedWriteHandler; import java.net.URI; public class HttpDownloadClient { /** * Download http resources, download to the server, and directly fill in the relative path of the file to be downloaded * (βββIt is recommended to use only letters and numbers for special characters. Partial filtering of characters may lead to exceptions ↑ ↑ ↑) * Enter the full path to the Internet download * @param host Destination host ip or domain name * @param port Target host port * @param url File path * @param local Local storage path * @throws Exception */ public void connect(String host, int port, String url, final String local) throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup); b.channel(NioSocketChannel.class); b.option(ChannelOption.SO_KEEPALIVE, true); b.handler(new ChildChannelHandler(local)); // Start the client. ChannelFuture f = b.connect(host, port).sync(); URI uri = new URI(url); DefaultFullHttpRequest request = new DefaultFullHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString()); // Build http request request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, request.content().readableBytes()); // Send http request f.channel().write(request); f.channel().flush(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } } private class ChildChannelHandler extends ChannelInitializer<SocketChannel> { String local; public ChildChannelHandler(String local) { this.local = local; } @Override protected void initChannel(SocketChannel ch) throws Exception { // The client receives an httpResponse response, so it needs to use HttpResponseDecoder for decoding ch.pipeline().addLast(new HttpResponseDecoder()); // The client sends httprequest, so httprequest encoder should be used for encoding ch.pipeline().addLast(new HttpRequestEncoder()); ch.pipeline().addLast(new ChunkedWriteHandler()); ch.pipeline().addLast(new HttpDownloadHandler(local)); } } public static void main(String[] args) throws Exception { HttpDownloadClient client = new HttpDownloadClient(); //client.connect("127.0.0.1", 9003,"/file/pppp/1.doc","1.doc"); // client.connect("zlysix.gree.com", 80, "http://zlysix.gree.com/HelloWeb/download/20m.apk", "20m.apk"); client.connect("www.ghost64.com", 80, "http://www.ghost64.com/qqtupian/zixunImg/local/2017/05/27/1495855297602.jpg", "1495855297602.jpg"); } }
client side handler:
import java.io.File; import java.io.FileOutputStream; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.http.HttpContent; //import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.LastHttpContent; import io.netty.util.internal.SystemPropertyUtil; /** * @Author:yangyue * @Description: * @Date: Created in 9:15 on 2017/5/28. */ public class HttpDownloadHandler extends ChannelInboundHandlerAdapter { private boolean readingChunks = false; // Block reading switch private FileOutputStream fOutputStream = null;// File output stream private File localfile = null;// Local object to download file private String local = null;// File name to be downloaded private int succCode;// Status code public HttpDownloadHandler(String local) { this.local = local; } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof HttpResponse) {// response header information HttpResponse response = (HttpResponse) msg; succCode = response.getStatus().code(); if (succCode == 200) { setDownLoadFile();// Set download file readingChunks = true; } // System.out.println("CONTENT_TYPE:" // + response.headers().get(HttpHeaders.Names.CONTENT_TYPE)); } if (msg instanceof HttpContent) {// response body information HttpContent chunk = (HttpContent) msg; if (chunk instanceof LastHttpContent) { readingChunks = false; } ByteBuf buffer = chunk.content(); byte[] dst = new byte[buffer.readableBytes()]; if (succCode == 200) { while (buffer.isReadable()) { buffer.readBytes(dst); fOutputStream.write(dst); buffer.release(); } if (null != fOutputStream) { fOutputStream.flush(); } } } if (!readingChunks) { if (null != fOutputStream) { System.out.println("Download done->"+ localfile.getAbsolutePath()); fOutputStream.flush(); fOutputStream.close(); localfile = null; fOutputStream = null; } ctx.channel().close(); } } /** * Configure local parameters for download */ private void setDownLoadFile() throws Exception { if (null == fOutputStream) { local = SystemPropertyUtil.get("user.dir") + File.separator +local; //System.out.println(local); localfile = new File(local); if (!localfile.exists()) { localfile.createNewFile(); } fOutputStream = new FileOutputStream(localfile); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { System.out.println("Pipeline abnormality:" + cause.getMessage()); cause.printStackTrace(); ctx.channel().close(); } }
Here, I put a network connection and downloaded a picture. Start the server and client to see that the picture has been downloaded to the root directory of the project.
Recent hot article recommendations:
1.1000 + Java interview questions and answers (2021 latest version)
2.Finally got the IntelliJ IDEA activation code through the open source project. It's really fragrant!
3.Ali Mock tools are officially open source and kill all Mock tools on the market!
4.Spring Cloud 2020.0.0 is officially released, a new and subversive version!
5.Java development manual (Songshan version) is the latest release. Download it quickly!
Feel good, don't forget to like + forward!