netty去实现文件传输

桃扇骨 2022-06-08 08:14 301阅读 0赞

在写出了Netty Hello World 和 netty对象传输之后,又觉得不够,看了官网的例子,所以有了现在的这个文件传输。
顺便说下,netty官网的例子真的好,如果要学习netty,还是看官网例子的好。
不过我英文不太好,刚开始走了绕了好大一圈,但是现在熟悉了之后,回过头来看,还是官网的牛X。
在这里再说下netty的零拷贝,这个零拷贝是netty在3.2版本中新加入的功能。
其主要指的是在进行一些比较大的传输比如对象或者文件传输的时候,通过改变数组索引的方式,将数据传输到特定的channel上。
是的channel之间的转换是零拷贝,例如:ByteBuffer和ChannelBuffer
下面就把文件传输的例子贴出来吧。
1、FileClient.java

[java] view plain copy 在CODE上查看代码片 派生到我的代码片

  1. package filetrans;
  2. import static org.jboss.netty.channel.Channels.pipeline;
  3. import java.net.InetSocketAddress;
  4. import java.util.concurrent.Executors;
  5. import org.jboss.netty.bootstrap.ClientBootstrap;
  6. import org.jboss.netty.channel.ChannelFuture;
  7. import org.jboss.netty.channel.ChannelPipeline;
  8. import org.jboss.netty.channel.ChannelPipelineFactory;
  9. import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
  10. import org.jboss.netty.handler.codec.http.DefaultHttpRequest;
  11. import org.jboss.netty.handler.codec.http.HttpMethod;
  12. import org.jboss.netty.handler.codec.http.HttpRequest;
  13. import org.jboss.netty.handler.codec.http.HttpRequestEncoder;
  14. import org.jboss.netty.handler.codec.http.HttpResponseDecoder;
  15. import org.jboss.netty.handler.codec.http.HttpVersion;
  16. import org.jboss.netty.handler.stream.ChunkedWriteHandler;
  17. public class FileClient
  18. {
  19. public static void main(String[] args)
  20. {
  21. ClientBootstrap bootstrap = new ClientBootstrap(
  22. new NioClientSocketChannelFactory(
  23. Executors.newCachedThreadPool(),
  24. Executors.newCachedThreadPool()));
  25. bootstrap.setPipelineFactory(new ChannelPipelineFactory()
  26. {
  27. @Override
  28. public ChannelPipeline getPipeline() throws Exception
  29. {
  30. ChannelPipeline pipeline = pipeline();
  31. pipeline.addLast(“decoder”, new HttpResponseDecoder());
  32. /*
  33. * 不能添加这个,对传输文件 进行了大小的限制。。。。。
  34. */
  35. // pipeline.addLast(“aggregator”, new HttpChunkAggregator(6048576));
  36. pipeline.addLast(“encoder”, new HttpRequestEncoder());
  37. pipeline.addLast(“chunkedWriter”, new ChunkedWriteHandler());
  38. pipeline.addLast(“handler”, new FileClientHandler());
  39. return pipeline;
  40. }
  41. });
  42. ChannelFuture future = bootstrap.connect(new InetSocketAddress(
  43. “localhost”, 8080));
  44. /*
  45. * 这里为了保证connect连接,所以才进行了sleep
  46. * 当然也可以通过future的connect属性判断
  47. */
  48. try
  49. {
  50. Thread.sleep(3000);
  51. } catch (InterruptedException e)
  52. {
  53. e.printStackTrace();
  54. }
  55. HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
  56. HttpMethod.GET, “DSC01575.JPG”);
  57. future.getChannel().write(request);
  58. // Wait until the connection is closed or the connection attempt fails.
  59. future.getChannel().getCloseFuture().awaitUninterruptibly();
  60. // Shut down thread pools to exit.
  61. bootstrap.releaseExternalResources();
  62. }
  63. }

[java] view plain copy

  1. package filetrans;
  2. import static org.jboss.netty.channel.Channels.pipeline;
  3. import java.net.InetSocketAddress;
  4. import java.util.concurrent.Executors;
  5. import org.jboss.netty.bootstrap.ClientBootstrap;
  6. import org.jboss.netty.channel.ChannelFuture;
  7. import org.jboss.netty.channel.ChannelPipeline;
  8. import org.jboss.netty.channel.ChannelPipelineFactory;
  9. import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
  10. import org.jboss.netty.handler.codec.http.DefaultHttpRequest;
  11. import org.jboss.netty.handler.codec.http.HttpMethod;
  12. import org.jboss.netty.handler.codec.http.HttpRequest;
  13. import org.jboss.netty.handler.codec.http.HttpRequestEncoder;
  14. import org.jboss.netty.handler.codec.http.HttpResponseDecoder;
  15. import org.jboss.netty.handler.codec.http.HttpVersion;
  16. import org.jboss.netty.handler.stream.ChunkedWriteHandler;
  17. public class FileClient
  18. {
  19. public static void main(String[] args)
  20. {
  21. ClientBootstrap bootstrap = new ClientBootstrap(
  22. new NioClientSocketChannelFactory(
  23. Executors.newCachedThreadPool(),
  24. Executors.newCachedThreadPool()));
  25. bootstrap.setPipelineFactory(new ChannelPipelineFactory()
  26. {
  27. @Override
  28. public ChannelPipeline getPipeline() throws Exception
  29. {
  30. ChannelPipeline pipeline = pipeline();
  31. pipeline.addLast(“decoder”, new HttpResponseDecoder());
  32. /*
  33. * 不能添加这个,对传输文件 进行了大小的限制。。。。。
  34. */
  35. // pipeline.addLast(“aggregator”, new HttpChunkAggregator(6048576));
  36. pipeline.addLast(“encoder”, new HttpRequestEncoder());
  37. pipeline.addLast(“chunkedWriter”, new ChunkedWriteHandler());
  38. pipeline.addLast(“handler”, new FileClientHandler());
  39. return pipeline;
  40. }
  41. });
  42. ChannelFuture future = bootstrap.connect(new InetSocketAddress(
  43. “localhost”, 8080));
  44. /*
  45. * 这里为了保证connect连接,所以才进行了sleep
  46. * 当然也可以通过future的connect属性判断
  47. */
  48. try
  49. {
  50. Thread.sleep(3000);
  51. } catch (InterruptedException e)
  52. {
  53. e.printStackTrace();
  54. }
  55. HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
  56. HttpMethod.GET, “DSC01575.JPG”);
  57. future.getChannel().write(request);
  58. // Wait until the connection is closed or the connection attempt fails.
  59. future.getChannel().getCloseFuture().awaitUninterruptibly();
  60. // Shut down thread pools to exit.
  61. bootstrap.releaseExternalResources();
  62. }
  63. }

2、FileClientHandler.java

[java] view plain copy 在CODE上查看代码片 派生到我的代码片

  1. package filetrans;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import org.jboss.netty.buffer.ChannelBuffer;
  5. import org.jboss.netty.channel.ChannelHandlerContext;
  6. import org.jboss.netty.channel.ExceptionEvent;
  7. import org.jboss.netty.channel.MessageEvent;
  8. import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
  9. import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
  10. import org.jboss.netty.handler.codec.http.HttpChunk;
  11. import org.jboss.netty.handler.codec.http.HttpResponse;
  12. public class FileClientHandler extends SimpleChannelUpstreamHandler
  13. {
  14. private volatile boolean readingChunks;
  15. private File downloadFile;
  16. private FileOutputStream fOutputStream = null;
  17. @Override
  18. public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
  19. throws Exception
  20. {
  21. /*
  22. * 按照channle的顺序进行处理
  23. * server先发送HttpResponse过来,所以这里先对HttpResponse进行处理,进行文件判断之类
  24. * 之后,server发送的都是ChunkedFile了。
  25. */
  26. if (e.getMessage() instanceof HttpResponse)
  27. {
  28. DefaultHttpResponse httpResponse = (DefaultHttpResponse) e
  29. .getMessage();
  30. String fileName = httpResponse.getHeader(“fileName”);
  31. downloadFile = new File(System.getProperty(“user.dir”)
    • File.separator + “recived_“ + fileName);
  32. readingChunks = httpResponse.isChunked();
  33. } else
  34. {
  35. HttpChunk httpChunk = (HttpChunk) e.getMessage();
  36. if (!httpChunk.isLast())
  37. {
  38. ChannelBuffer buffer = httpChunk.getContent();
  39. if (fOutputStream == null)
  40. {
  41. fOutputStream = new FileOutputStream(downloadFile);
  42. }
  43. while (buffer.readable())
  44. {
  45. byte[] dst = new byte[buffer.readableBytes()];
  46. buffer.readBytes(dst);
  47. fOutputStream.write(dst);
  48. }
  49. } else
  50. {
  51. readingChunks = false;
  52. }
  53. fOutputStream.flush();
  54. }
  55. if (!readingChunks)
  56. {
  57. fOutputStream.close();
  58. e.getChannel().close();
  59. }
  60. }
  61. @Override
  62. public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
  63. throws Exception
  64. {
  65. System.out.println(e.getCause());
  66. }
  67. }

[java] view plain copy

  1. package filetrans;
  2. import java.io.File;
  3. import java.io.FileOutputStream;
  4. import org.jboss.netty.buffer.ChannelBuffer;
  5. import org.jboss.netty.channel.ChannelHandlerContext;
  6. import org.jboss.netty.channel.ExceptionEvent;
  7. import org.jboss.netty.channel.MessageEvent;
  8. import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
  9. import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
  10. import org.jboss.netty.handler.codec.http.HttpChunk;
  11. import org.jboss.netty.handler.codec.http.HttpResponse;
  12. public class FileClientHandler extends SimpleChannelUpstreamHandler
  13. {
  14. private volatile boolean readingChunks;
  15. private File downloadFile;
  16. private FileOutputStream fOutputStream = null;
  17. @Override
  18. public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
  19. throws Exception
  20. {
  21. /*
  22. * 按照channle的顺序进行处理
  23. * server先发送HttpResponse过来,所以这里先对HttpResponse进行处理,进行文件判断之类
  24. * 之后,server发送的都是ChunkedFile了。
  25. */
  26. if (e.getMessage() instanceof HttpResponse)
  27. {
  28. DefaultHttpResponse httpResponse = (DefaultHttpResponse) e
  29. .getMessage();
  30. String fileName = httpResponse.getHeader(“fileName”);
  31. downloadFile = new File(System.getProperty(“user.dir”)
    • File.separator + “recived_“ + fileName);
  32. readingChunks = httpResponse.isChunked();
  33. } else
  34. {
  35. HttpChunk httpChunk = (HttpChunk) e.getMessage();
  36. if (!httpChunk.isLast())
  37. {
  38. ChannelBuffer buffer = httpChunk.getContent();
  39. if (fOutputStream == null)
  40. {
  41. fOutputStream = new FileOutputStream(downloadFile);
  42. }
  43. while (buffer.readable())
  44. {
  45. byte[] dst = new byte[buffer.readableBytes()];
  46. buffer.readBytes(dst);
  47. fOutputStream.write(dst);
  48. }
  49. } else
  50. {
  51. readingChunks = false;
  52. }
  53. fOutputStream.flush();
  54. }
  55. if (!readingChunks)
  56. {
  57. fOutputStream.close();
  58. e.getChannel().close();
  59. }
  60. }
  61. @Override
  62. public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
  63. throws Exception
  64. {
  65. System.out.println(e.getCause());
  66. }
  67. }

3、FileServer.java

[java] view plain copy 在CODE上查看代码片 派生到我的代码片

  1. package filetrans;
  2. import static org.jboss.netty.channel.Channels.pipeline;
  3. import java.net.InetSocketAddress;
  4. import java.util.concurrent.Executors;
  5. import org.jboss.netty.bootstrap.ServerBootstrap;
  6. import org.jboss.netty.channel.ChannelPipeline;
  7. import org.jboss.netty.channel.ChannelPipelineFactory;
  8. import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
  9. import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
  10. import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
  11. import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
  12. import org.jboss.netty.handler.stream.ChunkedWriteHandler;
  13. public class FileServer
  14. {
  15. public static void main(String[] args)
  16. {
  17. ServerBootstrap bootstrap = new ServerBootstrap(
  18. new NioServerSocketChannelFactory(
  19. Executors.newCachedThreadPool(),
  20. Executors.newCachedThreadPool()));
  21. bootstrap.setPipelineFactory(new ChannelPipelineFactory()
  22. {
  23. @Override
  24. public ChannelPipeline getPipeline() throws Exception
  25. {
  26. ChannelPipeline pipeline = pipeline();
  27. pipeline.addLast(“decoder”, new HttpRequestDecoder());
  28. pipeline.addLast(“aggregator”, new HttpChunkAggregator(65536));
  29. pipeline.addLast(“encoder”, new HttpResponseEncoder());
  30. pipeline.addLast(“chunkedWriter”, new ChunkedWriteHandler());
  31. pipeline.addLast(“handler”, new FileServerHandler());
  32. return pipeline;
  33. }
  34. });
  35. bootstrap.bind(new InetSocketAddress(8080));
  36. }
  37. }

[java] view plain copy

  1. package filetrans;
  2. import static org.jboss.netty.channel.Channels.pipeline;
  3. import java.net.InetSocketAddress;
  4. import java.util.concurrent.Executors;
  5. import org.jboss.netty.bootstrap.ServerBootstrap;
  6. import org.jboss.netty.channel.ChannelPipeline;
  7. import org.jboss.netty.channel.ChannelPipelineFactory;
  8. import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
  9. import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
  10. import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
  11. import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
  12. import org.jboss.netty.handler.stream.ChunkedWriteHandler;
  13. public class FileServer
  14. {
  15. public static void main(String[] args)
  16. {
  17. ServerBootstrap bootstrap = new ServerBootstrap(
  18. new NioServerSocketChannelFactory(
  19. Executors.newCachedThreadPool(),
  20. Executors.newCachedThreadPool()));
  21. bootstrap.setPipelineFactory(new ChannelPipelineFactory()
  22. {
  23. @Override
  24. public ChannelPipeline getPipeline() throws Exception
  25. {
  26. ChannelPipeline pipeline = pipeline();
  27. pipeline.addLast(“decoder”, new HttpRequestDecoder());
  28. pipeline.addLast(“aggregator”, new HttpChunkAggregator(65536));
  29. pipeline.addLast(“encoder”, new HttpResponseEncoder());
  30. pipeline.addLast(“chunkedWriter”, new ChunkedWriteHandler());
  31. pipeline.addLast(“handler”, new FileServerHandler());
  32. return pipeline;
  33. }
  34. });
  35. bootstrap.bind(new InetSocketAddress(8080));
  36. }
  37. }

4、FileServerHandler.java

[java] view plain copy 在CODE上查看代码片 派生到我的代码片

  1. package filetrans;
  2. import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
  3. import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
  4. import static org.jboss.netty.handler.codec.http.HttpMethod.*;
  5. import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
  6. import static org.jboss.netty.handler.codec.http.HttpVersion.*;
  7. import java.io.File;
  8. import java.io.FileNotFoundException;
  9. import java.io.RandomAccessFile;
  10. import java.io.UnsupportedEncodingException;
  11. import java.net.URLDecoder;
  12. import org.jboss.netty.buffer.ChannelBuffers;
  13. import org.jboss.netty.channel.Channel;
  14. import org.jboss.netty.channel.ChannelFuture;
  15. import org.jboss.netty.channel.ChannelFutureListener;
  16. import org.jboss.netty.channel.ChannelFutureProgressListener;
  17. import org.jboss.netty.channel.ChannelHandlerContext;
  18. import org.jboss.netty.channel.DefaultFileRegion;
  19. import org.jboss.netty.channel.ExceptionEvent;
  20. import org.jboss.netty.channel.FileRegion;
  21. import org.jboss.netty.channel.MessageEvent;
  22. import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
  23. import org.jboss.netty.handler.codec.frame.TooLongFrameException;
  24. import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
  25. import org.jboss.netty.handler.codec.http.HttpRequest;
  26. import org.jboss.netty.handler.codec.http.HttpResponse;
  27. import org.jboss.netty.handler.codec.http.HttpResponseStatus;
  28. import org.jboss.netty.handler.ssl.SslHandler;
  29. import org.jboss.netty.handler.stream.ChunkedFile;
  30. import org.jboss.netty.util.CharsetUtil;
  31. /**
  32. * 这里的代码主要来源于官网的例子,http里面有个例子,自己仿照server写了client
  33. * @author Ransom
  34. */
  35. public class FileServerHandler extends SimpleChannelUpstreamHandler
  36. {
  37. @Override
  38. public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
  39. throws Exception
  40. {
  41. HttpRequest request = (HttpRequest) e.getMessage();
  42. if (request.getMethod() != GET)
  43. {
  44. sendError(ctx, METHOD_NOT_ALLOWED);
  45. return;
  46. }
  47. final String path = sanitizeUri(request.getUri());
  48. if (path == null)
  49. {
  50. sendError(ctx, FORBIDDEN);
  51. return;
  52. }
  53. File file = new File(path);
  54. if (file.isHidden() || !file.exists())
  55. {
  56. sendError(ctx, NOT_FOUND);
  57. return;
  58. }
  59. if (!file.isFile())
  60. {
  61. sendError(ctx, FORBIDDEN);
  62. return;
  63. }
  64. RandomAccessFile raf;
  65. try
  66. {
  67. raf = new RandomAccessFile(file, “r”);
  68. } catch (FileNotFoundException fnfe)
  69. {
  70. sendError(ctx, NOT_FOUND);
  71. return;
  72. }
  73. long fileLength = raf.length();
  74. HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
  75. /*
  76. * 由于是异步传输,所以不得已加入了一些属性,用来进行文件识别
  77. */
  78. response.addHeader(“fileName”, request.getUri());
  79. setContentLength(response, fileLength);
  80. Channel ch = e.getChannel();
  81. // Write the initial line and the header.
  82. ch.write(response);
  83. // Write the content.
  84. ChannelFuture writeFuture;
  85. if (ch.getPipeline().get(SslHandler.class) != null)
  86. {
  87. // Cannot use zero-copy with HTTPS.
  88. writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192));
  89. } else
  90. {
  91. // No encryption - use zero-copy.
  92. final FileRegion region = new DefaultFileRegion(raf.getChannel(),
  93. 0, fileLength);
  94. writeFuture = ch.write(region);
  95. writeFuture.addListener(new ChannelFutureProgressListener()
  96. {
  97. public void operationComplete(ChannelFuture future)
  98. {
  99. region.releaseExternalResources();
  100. }
  101. public void operationProgressed(ChannelFuture future,
  102. long amount, long current, long total)
  103. {
  104. System.out.printf(“%s: %d / %d (+%d)%n”, path, current,
  105. total, amount);
  106. }
  107. });
  108. }
  109. // Decide whether to close the connection or not.
  110. if (!isKeepAlive(request))
  111. {
  112. // Close the connection when the whole content is written out.
  113. writeFuture.addListener(ChannelFutureListener.CLOSE);
  114. }
  115. }
  116. @Override
  117. public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
  118. throws Exception
  119. {
  120. Channel ch = e.getChannel();
  121. Throwable cause = e.getCause();
  122. if (cause instanceof TooLongFrameException)
  123. {
  124. sendError(ctx, BAD_REQUEST);
  125. return;
  126. }
  127. cause.printStackTrace();
  128. if (ch.isConnected())
  129. {
  130. sendError(ctx, INTERNAL_SERVER_ERROR);
  131. }
  132. }
  133. private String sanitizeUri(String uri)
  134. {
  135. // Decode the path.
  136. try
  137. {
  138. uri = URLDecoder.decode(uri, “UTF-8”);
  139. } catch (UnsupportedEncodingException e)
  140. {
  141. try
  142. {
  143. uri = URLDecoder.decode(uri, “ISO-8859-1”);
  144. } catch (UnsupportedEncodingException e1)
  145. {
  146. throw new Error();
  147. }
  148. }
  149. // Convert file separators.
  150. uri = uri.replace(‘/‘, File.separatorChar);
  151. // Simplistic dumb security check.
  152. // You will have to do something serious in the production environment.
  153. if (uri.contains(File.separator + “.”)
  154. || uri.contains(“.” + File.separator) || uri.startsWith(“.”)
  155. || uri.endsWith(“.”))
  156. {
  157. return null;
  158. }
  159. // Convert to absolute path.
  160. return System.getProperty(“user.dir”) + File.separator + uri;
  161. }
  162. private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status)
  163. {
  164. HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
  165. response.setHeader(CONTENT_TYPE, “text/plain; charset=UTF-8”);
  166. response.setContent(ChannelBuffers.copiedBuffer(
  167. “Failure: “ + status.toString() + “\r\n”, CharsetUtil.UTF_8));
  168. // Close the connection as soon as the error message is sent.
  169. ctx.getChannel().write(response)
  170. .addListener(ChannelFutureListener.CLOSE);
  171. }
  172. }

[java] view plain copy

  1. package filetrans;
  2. import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
  3. import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
  4. import static org.jboss.netty.handler.codec.http.HttpMethod.*;
  5. import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
  6. import static org.jboss.netty.handler.codec.http.HttpVersion.*;
  7. import java.io.File;
  8. import java.io.FileNotFoundException;
  9. import java.io.RandomAccessFile;
  10. import java.io.UnsupportedEncodingException;
  11. import java.net.URLDecoder;
  12. import org.jboss.netty.buffer.ChannelBuffers;
  13. import org.jboss.netty.channel.Channel;
  14. import org.jboss.netty.channel.ChannelFuture;
  15. import org.jboss.netty.channel.ChannelFutureListener;
  16. import org.jboss.netty.channel.ChannelFutureProgressListener;
  17. import org.jboss.netty.channel.ChannelHandlerContext;
  18. import org.jboss.netty.channel.DefaultFileRegion;
  19. import org.jboss.netty.channel.ExceptionEvent;
  20. import org.jboss.netty.channel.FileRegion;
  21. import org.jboss.netty.channel.MessageEvent;
  22. import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
  23. import org.jboss.netty.handler.codec.frame.TooLongFrameException;
  24. import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
  25. import org.jboss.netty.handler.codec.http.HttpRequest;
  26. import org.jboss.netty.handler.codec.http.HttpResponse;
  27. import org.jboss.netty.handler.codec.http.HttpResponseStatus;
  28. import org.jboss.netty.handler.ssl.SslHandler;
  29. import org.jboss.netty.handler.stream.ChunkedFile;
  30. import org.jboss.netty.util.CharsetUtil;
  31. /**
  32. * 这里的代码主要来源于官网的例子,http里面有个例子,自己仿照server写了client
  33. * @author Ransom
  34. */
  35. public class FileServerHandler extends SimpleChannelUpstreamHandler
  36. {
  37. @Override
  38. public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
  39. throws Exception
  40. {
  41. HttpRequest request = (HttpRequest) e.getMessage();
  42. if (request.getMethod() != GET)
  43. {
  44. sendError(ctx, METHOD_NOT_ALLOWED);
  45. return;
  46. }
  47. final String path = sanitizeUri(request.getUri());
  48. if (path == null)
  49. {
  50. sendError(ctx, FORBIDDEN);
  51. return;
  52. }
  53. File file = new File(path);
  54. if (file.isHidden() || !file.exists())
  55. {
  56. sendError(ctx, NOT_FOUND);
  57. return;
  58. }
  59. if (!file.isFile())
  60. {
  61. sendError(ctx, FORBIDDEN);
  62. return;
  63. }
  64. RandomAccessFile raf;
  65. try
  66. {
  67. raf = new RandomAccessFile(file, “r”);
  68. } catch (FileNotFoundException fnfe)
  69. {
  70. sendError(ctx, NOT_FOUND);
  71. return;
  72. }
  73. long fileLength = raf.length();
  74. HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
  75. /*
  76. * 由于是异步传输,所以不得已加入了一些属性,用来进行文件识别
  77. */
  78. response.addHeader(“fileName”, request.getUri());
  79. setContentLength(response, fileLength);
  80. Channel ch = e.getChannel();
  81. // Write the initial line and the header.
  82. ch.write(response);
  83. // Write the content.
  84. ChannelFuture writeFuture;
  85. if (ch.getPipeline().get(SslHandler.class) != null)
  86. {
  87. // Cannot use zero-copy with HTTPS.
  88. writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192));
  89. } else
  90. {
  91. // No encryption - use zero-copy.
  92. final FileRegion region = new DefaultFileRegion(raf.getChannel(),
  93. 0, fileLength);
  94. writeFuture = ch.write(region);
  95. writeFuture.addListener(new ChannelFutureProgressListener()
  96. {
  97. public void operationComplete(ChannelFuture future)
  98. {
  99. region.releaseExternalResources();
  100. }
  101. public void operationProgressed(ChannelFuture future,
  102. long amount, long current, long total)
  103. {
  104. System.out.printf(“%s: %d / %d (+%d)%n”, path, current,
  105. total, amount);
  106. }
  107. });
  108. }
  109. // Decide whether to close the connection or not.
  110. if (!isKeepAlive(request))
  111. {
  112. // Close the connection when the whole content is written out.
  113. writeFuture.addListener(ChannelFutureListener.CLOSE);
  114. }
  115. }
  116. @Override
  117. public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
  118. throws Exception
  119. {
  120. Channel ch = e.getChannel();
  121. Throwable cause = e.getCause();
  122. if (cause instanceof TooLongFrameException)
  123. {
  124. sendError(ctx, BAD_REQUEST);
  125. return;
  126. }
  127. cause.printStackTrace();
  128. if (ch.isConnected())
  129. {
  130. sendError(ctx, INTERNAL_SERVER_ERROR);
  131. }
  132. }
  133. private String sanitizeUri(String uri)
  134. {
  135. // Decode the path.
  136. try
  137. {
  138. uri = URLDecoder.decode(uri, “UTF-8”);
  139. } catch (UnsupportedEncodingException e)
  140. {
  141. try
  142. {
  143. uri = URLDecoder.decode(uri, “ISO-8859-1”);
  144. } catch (UnsupportedEncodingException e1)
  145. {
  146. throw new Error();
  147. }
  148. }
  149. // Convert file separators.
  150. uri = uri.replace(‘/‘, File.separatorChar);
  151. // Simplistic dumb security check.
  152. // You will have to do something serious in the production environment.
  153. if (uri.contains(File.separator + “.”)
  154. || uri.contains(“.” + File.separator) || uri.startsWith(“.”)
  155. || uri.endsWith(“.”))
  156. {
  157. return null;
  158. }
  159. // Convert to absolute path.
  160. return System.getProperty(“user.dir”) + File.separator + uri;
  161. }
  162. private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status)
  163. {
  164. HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
  165. response.setHeader(CONTENT_TYPE, “text/plain; charset=UTF-8”);
  166. response.setContent(ChannelBuffers.copiedBuffer(
  167. “Failure: “ + status.toString() + “\r\n”, CharsetUtil.UTF_8));
  168. // Close the connection as soon as the error message is sent.
  169. ctx.getChannel().write(response)
  170. .addListener(ChannelFutureListener.CLOSE);
  171. }
  172. }

Netty的例子到这里就算贴完了,后面还打算进行一些Netty实现原理,架构,代码解读方面的分析。到时候如果有什么心得,再写出来吧。

发表评论

表情:
评论列表 (有 0 条评论,301人围观)

还没有评论,来说两句吧...

相关阅读

    相关 netty传输java bean对象

    在上一篇博客(netty入门实现简单的echo程序)中,我们知道了如何使用netty发送一个简单的消息,但是这远远是不够的。在这篇博客中,我们来使用netty发送一个java

    相关 Netty权威指南之文件传输

    本章相关知识点: 文件是最常见的数据源之一,在程序经常需要将数据存储到文件中,比如:图片文件、声音文件等数据文件。在实际使用中,文件都包含一个特定的格式,这个格式需要程序员根

    相关 netty实现文件传输

    在写出了Netty Hello World 和 netty对象传输之后,又觉得不够,看了官网的例子,所以有了现在的这个文件传输。 顺便说下,netty官网的例子真的好,如果