netty

  1. package com.dxz.nettydemo.http;
  2.  
  3. import java.io.UnsupportedEncodingException;
  4.  
  5. import io.netty.buffer.Unpooled;
  6. import io.netty.channel.ChannelHandlerContext;
  7. import io.netty.channel.ChannelInboundHandlerAdapter;
  8. import io.netty.handler.codec.http.DefaultFullHttpResponse;
  9. import io.netty.handler.codec.http.FullHttpResponse;
  10. import io.netty.handler.codec.http.HttpRequest;
  11. import io.netty.handler.codec.http.HttpResponseStatus;
  12. import io.netty.handler.codec.http.HttpVersion;
  13. import io.netty.handler.codec.http.QueryStringDecoder;
  14.  
  15. class HttpServerHandler extends ChannelInboundHandlerAdapter {
  16.  
  17. @Override
  18. public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
  19.  
  20. if (msg instanceof HttpRequest) {
  21.  
  22. // 请求,解码器将请求转换成HttpRequest对象
  23. HttpRequest request = (HttpRequest) msg;
  24.  
  25. // 获取请求参数
  26. QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());
  27. String name = "World";
  28. if (queryStringDecoder.parameters().get("name") != null) {
  29. name = queryStringDecoder.parameters().get("name").get(0);
  30. }
  31.  
  32. // 响应HTML
  33. String responseHtml = "<html><body>Hello, " + name + "</body></html>";
  34. byte[] responseBytes = responseHtml.getBytes("UTF-8");
  35. int contentLength = responseBytes.length;
  36.  
  37. // 构造FullHttpResponse对象,FullHttpResponse包含message body
  38. FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
  39. Unpooled.wrappedBuffer(responseBytes));
  40. response.headers().set("Content-Type", "text/html; charset=utf-8");
  41. response.headers().set("Content-Length", Integer.toString(contentLength));
  42.  
  43. ctx.writeAndFlush(response);
  44. }
  45. }
  46.  
  47. @Override
  48. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  49. cause.printStackTrace();
  50. ctx.close();
  51. }
  52. }

主类:

  1. package com.dxz.nettydemo.http;
  2.  
  3. import io.netty.bootstrap.ServerBootstrap;
  4. import io.netty.channel.ChannelFuture;
  5. import io.netty.channel.ChannelInitializer;
  6. import io.netty.channel.ChannelPipeline;
  7. import io.netty.channel.EventLoopGroup;
  8. import io.netty.channel.nio.NioEventLoopGroup;
  9. import io.netty.channel.socket.SocketChannel;
  10. import io.netty.channel.socket.nio.NioServerSocketChannel;
  11. import io.netty.handler.codec.http.HttpServerCodec;
  12.  
  13. public class HttpServer {
  14.  
  15. public static void main(String[] args) throws InterruptedException {
  16. EventLoopGroup bossGroup = new NioEventLoopGroup();
  17. EventLoopGroup workerGroup = new NioEventLoopGroup();
  18. try {
  19. ServerBootstrap b = new ServerBootstrap();
  20. b.group(bossGroup, workerGroup)
  21. .channel(NioServerSocketChannel.class)
  22. .childHandler(new ChannelInitializer<SocketChannel>() {
  23. @Override
  24. public void initChannel(SocketChannel ch) throws Exception {
  25. ChannelPipeline pipeline = ch.pipeline();
  26. pipeline.addLast(new HttpServerCodec());
  27. pipeline.addLast(new HttpServerHandler());
  28. }
  29. });
  30. ChannelFuture f = b.bind(8080).sync();
  31. f.channel().closeFuture().sync();
  32. } finally {
  33. workerGroup.shutdownGracefully();
  34. bossGroup.shutdownGracefully();
  35. }
  36. }
  37. }

测试:

用浏览器访问:http://localhost:8080/

netty构建的文件服务器

1、首先加入的是HTTP请求消息解码器
ch.pipeline().addLast("http-decoder", new HttpRequestDecoder());
2、第2添加HttpObjectAggregator解密器,其作用是将多个消息转换为单一的FullHttpRequest或者FullHttpResponse,原因是HTTP解码器在每个HTTP消息中会生成多个消息对象:有1、HttpRequest/HttpResponse;2、HttpContent;3、LastHttpContent;
ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
3、第3增加HTTP响应编码器,对HTTP响应信息进行编码
ch.pipeline().addLast("http-encoder", new HttpResponseEncoder());
4、第4Chunked handler的主要作用是支持异步发送大的码流(例如大的文件传输),但不占用过多的内存,防止发生JAVA内存溢出错误
ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
5、第5HttpFileServerHandler用于文件服务器的业务逻辑处理

  1. package com.dxz.nettydemo.http;
  2.  
  3. import io.netty.bootstrap.ServerBootstrap;
  4. import io.netty.channel.ChannelFuture;
  5. import io.netty.channel.ChannelInitializer;
  6. import io.netty.channel.EventLoopGroup;
  7. import io.netty.channel.nio.NioEventLoopGroup;
  8. import io.netty.channel.socket.SocketChannel;
  9. import io.netty.channel.socket.nio.NioServerSocketChannel;
  10. import io.netty.handler.codec.http.HttpObjectAggregator;
  11. import io.netty.handler.codec.http.HttpRequestDecoder;
  12. import io.netty.handler.codec.http.HttpResponseEncoder;
  13. import io.netty.handler.stream.ChunkedWriteHandler;
  14.  
  15. public class HttpFileServer {
  16.  
  17. private static final String DEFAULT_URL = "/src/main/java/com/dxz/nettydemo/http";
  18.  
  19. public void run(final int port, final String url) throws Exception {
  20. EventLoopGroup bossGroup = new NioEventLoopGroup();
  21. EventLoopGroup workerGroup = new NioEventLoopGroup();
  22. try {
  23. ServerBootstrap b = new ServerBootstrap();
  24. b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
  25. .childHandler(new ChannelInitializer<SocketChannel>() {
  26. @Override
  27. protected void initChannel(SocketChannel ch) throws Exception {
  28. //首先加入的是HTTP请求消息解码器
  29. ch.pipeline().addLast("http-decoder", new HttpRequestDecoder());
  30. //第2添加HttpObjectAggregator解密器,其作用是将多个消息转换为单一的FullHttpRequest或者FullHttpResponse,
  31. //原因是HTTP解码器在每个HTTP消息中会生成多个消息对象:有1、HttpRequest/HttpResponse;2、HttpContent;3、LastHttpContent;
  32. ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536));
  33. //第3增加HTTP响应编码器,对HTTP响应信息进行编码
  34. ch.pipeline().addLast("http-encoder", new HttpResponseEncoder());
  35. //第4Chunked handler的主要作用是支持异步发送大的码流(例如大的文件传输),但不占用过多的内存,防止发生JAVA内存溢出错误
  36. ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
  37. //第5HttpFileServerHandler用于文件服务器的业务逻辑处理
  38. ch.pipeline().addLast("fileServerHandler", new HttpFileServerHandler(url));
  39. }
  40. });
  41. ChannelFuture future = b.bind("localhost", port).sync();
  42. System.out.println("HTTP文件目录服务器启动,网址是 : " + "http://localhost:" + port + url);
  43. future.channel().closeFuture().sync();
  44. } finally {
  45. bossGroup.shutdownGracefully();
  46. workerGroup.shutdownGracefully();
  47. }
  48. }
  49.  
  50. public static void main(String[] args) throws Exception {
  51. int port = 8080;
  52. if (args.length > 0) {
  53. try {
  54. port = Integer.parseInt(args[0]);
  55. } catch (NumberFormatException e) {
  56. e.printStackTrace();
  57. }
  58. }
  59. String url = DEFAULT_URL;
  60. if (args.length > 1)
  61. url = args[1];
  62. new HttpFileServer().run(port, url);
  63. }
  64. }

文件读取下载

  1. package com.dxz.nettydemo.http;
  2.  
  3. import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;
  4. import static io.netty.handler.codec.http.HttpHeaders.setContentLength;
  5. import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
  6. import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
  7. import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION;
  8. import static io.netty.handler.codec.http.HttpMethod.GET;
  9. import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
  10. import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
  11. import static io.netty.handler.codec.http.HttpResponseStatus.FOUND;
  12. import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
  13. import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;
  14. import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
  15. import static io.netty.handler.codec.http.HttpResponseStatus.OK;
  16. import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
  17. import io.netty.buffer.ByteBuf;
  18. import io.netty.buffer.Unpooled;
  19. import io.netty.channel.ChannelFuture;
  20. import io.netty.channel.ChannelFutureListener;
  21. import io.netty.channel.ChannelHandlerContext;
  22. import io.netty.channel.ChannelProgressiveFuture;
  23. import io.netty.channel.ChannelProgressiveFutureListener;
  24. import io.netty.channel.SimpleChannelInboundHandler;
  25. import io.netty.handler.codec.http.DefaultFullHttpResponse;
  26. import io.netty.handler.codec.http.DefaultHttpResponse;
  27. import io.netty.handler.codec.http.FullHttpRequest;
  28. import io.netty.handler.codec.http.FullHttpResponse;
  29. import io.netty.handler.codec.http.HttpHeaders;
  30. import io.netty.handler.codec.http.HttpResponse;
  31. import io.netty.handler.codec.http.HttpResponseStatus;
  32. import io.netty.handler.codec.http.LastHttpContent;
  33. import io.netty.handler.stream.ChunkedFile;
  34. import io.netty.util.CharsetUtil;
  35.  
  36. import java.io.File;
  37. import java.io.FileNotFoundException;
  38. import java.io.RandomAccessFile;
  39. import java.io.UnsupportedEncodingException;
  40. import java.net.URLDecoder;
  41. import java.util.regex.Pattern;
  42.  
  43. import javax.activation.MimetypesFileTypeMap;
  44.  
  45. public class HttpFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
  46. private final String url;
  47.  
  48. public HttpFileServerHandler(String url) {
  49. this.url = url;
  50. }
  51.  
  52. @Override
  53. public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
  54. //http请求消息解码结果的判断,如果解码失败,直接返回构造HTTP400 错误返回
  55. if (!request.getDecoderResult().isSuccess()) {
  56. sendError(ctx, BAD_REQUEST);
  57. return;
  58. }
  59. if (request.getMethod() != GET) {
  60. sendError(ctx, METHOD_NOT_ALLOWED);
  61. return;
  62. }
  63. final String uri = request.getUri();
  64. final String path = sanitizeUri(uri);
  65. if (path == null) {
  66. sendError(ctx, FORBIDDEN);
  67. return;
  68. }
  69. File file = new File(path);
  70. if (file.isHidden() || !file.exists()) {
  71. sendError(ctx, NOT_FOUND);
  72. return;
  73. }
  74. if (file.isDirectory()) {
  75. if (uri.endsWith("/")) {
  76. sendListing(ctx, file);
  77. } else {
  78. sendRedirect(ctx, uri + '/');
  79. }
  80. return;
  81. }
  82. if (!file.isFile()) {
  83. sendError(ctx, FORBIDDEN);
  84. return;
  85. }
  86. RandomAccessFile randomAccessFile = null;
  87. try {
  88. randomAccessFile = new RandomAccessFile(file, "r");// 以只读的方式打开文件
  89. } catch (FileNotFoundException fnfe) {
  90. sendError(ctx, NOT_FOUND);
  91. return;
  92. }
  93.  
  94. //待下载文件的长度
  95. long fileLength = randomAccessFile.length();
  96. HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
  97. setContentLength(response, fileLength);
  98. setContentTypeHeader(response, file);
  99. if (isKeepAlive(request)) {
  100. response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
  101. }
  102. ctx.write(response);
  103. ChannelFuture sendFileFuture;
  104. //通过netty的ChunkedFile对象将文件写入到发送缓冲区
  105. sendFileFuture = ctx.write(new ChunkedFile(randomAccessFile, 0, fileLength, 8192), ctx.newProgressivePromise());
  106. sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
  107. public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
  108. if (total < 0) { // total unknown
  109. System.err.println("Transfer progress: " + progress);
  110. } else {
  111. System.err.println("Transfer progress: " + progress + " / " + total);
  112. }
  113. }
  114.  
  115. public void operationComplete(ChannelProgressiveFuture future) throws Exception {
  116. System.out.println("Transfer complete.");
  117. }
  118. });
  119. //使用chunked编码,最后需要发送一个编码结束 的空消息体,将LastHttpContent的EMPTY_LAST_CONTENT发送到缓冲区中,标识所有的消息体已经发送完成,同时
  120. //用flush方法将之前在发送缓冲区的消息刷新到SocketChannel中发送给对方
  121. ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
  122. //如果不是keep-alive,服务端在发送完成之后,服务端主动关闭连接
  123. if (!isKeepAlive(request)) {
  124. lastContentFuture.addListener(ChannelFutureListener.CLOSE);
  125. }
  126. }
  127.  
  128. @Override
  129. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  130. cause.printStackTrace();
  131. if (ctx.channel().isActive()) {
  132. sendError(ctx, INTERNAL_SERVER_ERROR);
  133. }
  134. }
  135.  
  136. private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*");
  137.  
  138. /**
  139. * 请求路径的处理
  140. * @param uri
  141. * @return
  142. */
  143. private String sanitizeUri(String uri) {
  144. try {
  145. uri = URLDecoder.decode(uri, "UTF-8");
  146. } catch (UnsupportedEncodingException e) {
  147. try {
  148. uri = URLDecoder.decode(uri, "ISO-8859-1");
  149. } catch (UnsupportedEncodingException e1) {
  150. throw new Error();
  151. }
  152. }
  153. if (!uri.startsWith(url)) {
  154. return null;
  155. }
  156. if (!uri.startsWith("/")) {
  157. return null;
  158. }
  159. uri = uri.replace('/', File.separatorChar);
  160. if (uri.contains(File.separator + '.') || uri.contains('.' + File.separator) || uri.startsWith(".")
  161. || uri.endsWith(".") || INSECURE_URI.matcher(uri).matches()) {
  162. return null;
  163. }
  164. return System.getProperty("user.dir") + File.separator + uri;
  165. }
  166.  
  167. private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[A-Za-z0-9][-_A-Za-z0-9\\.]*");
  168.  
  169. private static void sendListing(ChannelHandlerContext ctx, File dir) {
  170. //创建成功的HTTP响应消息
  171. FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK);
  172. //设置消息头类型
  173. response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
  174. //构造响应消息体
  175. StringBuilder buf = new StringBuilder();
  176. String dirPath = dir.getPath();
  177. buf.append("<!DOCTYPE html>\r\n");
  178. buf.append("<html><head><title>");
  179. buf.append(dirPath);
  180. buf.append(" 目录:");
  181. buf.append("</title></head><body>\r\n");
  182. buf.append("<h3>");
  183. buf.append(dirPath).append(" 目录:");
  184. buf.append("</h3>\r\n");
  185. buf.append("<ul>");
  186. buf.append("<li>链接:<a href=\"../\">..</a></li>\r\n");
  187. for (File f : dir.listFiles()) {
  188. if (f.isHidden() || !f.canRead()) {
  189. continue;
  190. }
  191. String name = f.getName();
  192. if (!ALLOWED_FILE_NAME.matcher(name).matches()) {
  193. continue;
  194. }
  195. buf.append("<li>链接:<a href=\"");
  196. buf.append(name);
  197. buf.append("\">");
  198. buf.append(name);
  199. buf.append("</a></li>\r\n");
  200. }
  201. buf.append("</ul></body></html>\r\n");
  202. //分配对应消息的缓冲对象
  203. ByteBuf buffer = Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8);
  204. //将缓冲区中的响应消息存放到HTTP应答消息中
  205. response.content().writeBytes(buffer);
  206. //释放缓冲区
  207. buffer.release();
  208. //将响应消息刷新到SocketChannel中
  209. ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
  210. }
  211.  
  212. private static void sendRedirect(ChannelHandlerContext ctx, String newUri) {
  213. FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, FOUND);
  214. response.headers().set(LOCATION, newUri);
  215. ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
  216. }
  217.  
  218. private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
  219. FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status,
  220. Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
  221. response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
  222. ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
  223. }
  224.  
  225. private static void setContentTypeHeader(HttpResponse response, File file) {
  226. MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
  227. response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
  228. }
  229. }

演示:

YII Framework学习教程-YII的日志的更多相关文章

  1. YII Framework学习教程-YII的异常处理

    异常无处不在,作为程序员,活着就是为了创造这些异常,然后修复这些异常而存在的.YII框架封装了PHP的异常,让异常处理起来更简单. 使用 YII处理错误和异常的配置方法: 你可以在入口文件中定义YII ...

  2. YII Framework学习教程-YII的Model-开发规范-路径别名-命名空间

    到这里,大概的YII开发已经基本可以,但是下面要将的所有课程,学完之后可以让你更爱YII.下面的教程是讲的MVC的M,model.数据,业务,代码的集中地区.所以开始之前,学学开发规范-路径别名-命名 ...

  3. YII Framework学习教程-YII的安全

    web应用的安全问题是很重要的,在“黑客”盛行的年代,你的网站可能明天都遭受着攻击,为了从某种程度上防止被攻击,YII提供了防止攻击的几种解决方案.当然这里讲的安全是片面的,但是值得一看. 官方提供的 ...

  4. YII Framework学习教程-YII的国际化

    一个web应用,发布到互联网,就是面向全球用户.用户在世界的各个角落都可以访问到你的web应用,当然要看你的网站和不和谐,不和谐的web应用在和谐社会是不让你访问的. YII提供了国际化的支持,可以让 ...

  5. Yii Framework 开发教程Zii组件-Tabs示例

    有关Yii Tab类: http://www.yiichina.com/api/CTabView http://www.yiichina.com/api/CJuiTabs http://blog.cs ...

  6. Yii 简明学习教程

    Yii是一个基于组件的高性能PHP框架,用于快速开发Web应用程序(下面内容基于Yii 1.1) 1. 典型的工作流 用户向入口脚本index.php发起请求 入口脚本加载应用配置config.php ...

  7. YII之yiic创建YII应用

    yii提供了强大的命令行工具来快速的创建相关组件和应用.下面就来讲解用yiic工具快速创建yii应用我的web目录在 d:\www下 yiiframework在 D:\www\yii\framewor ...

  8. Yii框架学习 新手教程(一)

    本人小菜鸟一仅仅,为了自我学习和交流PHP(jquery,linux,lamp,shell,javascript,server)等一系列的知识,小菜鸟创建了一个群.希望光临本博客的人能够进来交流.寻求 ...

  9. Yii框架的学习指南(策码秀才篇)1-1 如何认识Yii framework

    Yii的框架和其他框架的区别在于:它是更加 快速,安全,专业的PHP框架 Yii是一个高性能的,适用于开发WEB2.0应用的PHP框架. Yii是一个基于组件.用于开发大型 Web 应用的 高性能 P ...

随机推荐

  1. Linux软链接和硬链接

    Linux中的链接有两种方式,软链接和硬链接.本文试图清晰彻底的解释Linux中软链接和硬链接文件的区别. 1.Linux链接文件 1)软链接文件  软链接又叫符号链接,这个文件包含了另一个文件的路径 ...

  2. 复习一下,? extends T 和 ? super T

    前话 最近学一些杂七杂八的东西,都把基础给忘了. 比如Java泛型中的 ? extends T和 ? super T 吧. 刚看开源项目的时候遇到它,表情如下: 源码分析 直接用源码来讲解吧 pack ...

  3. 《mysql悲观锁总结和实践》-悲观锁

    最近学习了一下数据库的悲观锁和乐观锁,根据自己的理解和网上参考资料总结如下: 悲观锁介绍(百科): 悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持 ...

  4. ubuntu安装postgresql与postgis

    版本信息 ubuntu    14.04.1LTS postgresql   9.3.5 postgis       2.1.2 今天尝试着安装了postgis 2.1.2,(较简便的包安装,不是源码 ...

  5. 原生javascript-常用的函数

    [一]添加监听事件 addHandler:function(node,type,fn){if(node.addEventListener){ node.addEventListener(type,fn ...

  6. 使用Windows Azure PowerShell远程管理Windows Azure虚拟机

    对于Windows Azure,如果你还在使用windowsazure.com门户来管理虚拟机,那就显得不怎么高上大了.Windows Azure PowerShell 是一个功能强大的脚本环境,可用 ...

  7. 防止SQL注入和XSS攻击Filter

    nbsp;今天系统使用IBM的安全漏洞扫描工具扫描出一堆漏洞,下面的filter主要是解决防止SQL注入和XSS攻击 一个是Filter负责将请求的request包装一下. 一个是request包装器 ...

  8. SQL SERVER 常用字符类型的区别

    长度为 n 个字节的固定长度且非 Unicode 的字符数据.n 必须是一个介于 1 和 8,000 之间的数值.存储大小为 n 个字节.char 在 SQL-92 中的同义词为 character. ...

  9. DBContext

    http://www.entityframeworktutorial.net/EntityFramework4.3/dbcontext-vs-objectcontext.aspx As you hav ...

  10. 第一篇 ERP是什么?-从道的层面浅谈我的理解

    世界上称为ERP软件的软件很多,国外的有SAP,ORACLE,国内的有金蝶,用友,浪潮.这些由不同的厂商开发制作的软件总有其软件适用的场合.这个场合就是企业,而且是市场经济中的企业.个人是不会购买ER ...