6、netty http协议开发应用(netty学习笔记)
来源:互联网 发布:淘宝上的笛子怎么样 编辑:程序博客网 时间:2024/06/07 21:37
1、Netty http服务端入门
1.1http文件服务器。
package com.play.netty.http.fileserver;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.codec.http.HttpObjectAggregator;import io.netty.handler.codec.http.HttpRequestDecoder;import io.netty.handler.codec.http.HttpResponseEncoder;import io.netty.handler.stream.ChunkedWriteHandler;/*** 简单的基于HTTP的文件服务器* Created by IntelliJ IDEA.* User: GongQi* Date: 2017/9/25*/public class HttpFileServer { private static final String DEFAULT_URL = "/src/main/java/com/play/netty/"; public void run(String host, Integer port, final String url) throws InterruptedException { //启动2个线程组 final EventLoopGroup bossGrop = new NioEventLoopGroup(); EventLoopGroup workGrop = new NioEventLoopGroup(); try { //启动器 ServerBootstrap bootstrap = new ServerBootstrap(); //绑定线组 bootstrap.group(bossGrop, workGrop) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline() .addLast("http-decoder", new HttpRequestDecoder()); //它的作用是将多个消息转换为单一的FullHttpRequest或者FullHttpResponse //http解码器在每个http消息体中会生成多个消息对象 //(1)HttpRequest\HttpResponse //(2)HttpContent //(3)LastHttpContent socketChannel.pipeline() .addLast("http-aggregator", new HttpObjectAggregator(65536)); socketChannel.pipeline() .addLast("http-encoder", new HttpResponseEncoder()); //为了支持异步发送大码流,不占用过多内存防止内存溢出 socketChannel.pipeline() .addLast("http-chunked", new ChunkedWriteHandler()); //我们需要的业务处理器 socketChannel.pipeline() .addLast("fileServerHander", new HttpFileServerHander(url)); } }); //绑定端口 ChannelFuture channelFuture = bootstrap.bind(host, port).sync(); System.out.println("系统启动完毕........"); //同步等待 channelFuture.channel().closeFuture().sync(); } finally { bossGrop.shutdownGracefully(); workGrop.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { Integer port = 8080; String url = DEFAULT_URL; new HttpFileServer().run("localhost", port, url); }}
HttpFileServerHander.java
package com.play.netty.http.fileserver;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.*;import io.netty.handler.codec.http.*;import io.netty.handler.stream.ChunkedFile;import io.netty.util.CharsetUtil;import javax.activation.MimetypesFileTypeMap;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 static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION;import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;import static io.netty.handler.codec.http.HttpHeaders.setContentLength;import static io.netty.handler.codec.http.HttpMethod.GET;import static io.netty.handler.codec.http.HttpResponseStatus.*;import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;/*** Created by IntelliJ IDEA.* User: GongQi* Date: 2017/9/25*/public class HttpFileServerHander extends SimpleChannelInboundHandler<FullHttpRequest> { private final String url; private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*"); private static final Pattern ALLOWED_FILE_NAME = Pattern .compile("[A-Za-z0-9][-_A-Za-z0-9\\.]*"); public HttpFileServerHander(String url) { this.url = url; } public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { //如果解码失败则返回错误 if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST); return; } //如果不是get则报错 if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } //获取uri并加工 final String uri = request.getUri(); final String path = sanitizeUri(uri); if (path == null) { sendError(ctx, FORBIDDEN); return; } // //获取文件 File file = new File(path); if (file.isHidden() || !file.exists()) { sendError(ctx, NOT_FOUND); return; } //如果是目录则返回目录信息 if (file.isDirectory()) { if (uri.endsWith("/")) { sendListing(ctx, file); } else { sendRedirect(ctx, uri + "/"); } return; } if(!file.isFile()){ sendError(ctx,FORBIDDEN); } RandomAccessFile randomAccessFile; try { randomAccessFile = new RandomAccessFile(file, "r"); } catch (FileNotFoundException e) { sendError(ctx, NOT_FOUND); return; } //获取文件的长度 long fileLength = randomAccessFile.length(); //构造HTTP应答消息,这边不能用FullHttpResponse,原因后续再说。 HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); setContentLength(response, fileLength); setContentTypeHeader(response, file); //判断是否keep-alive if (isKeepAlive(request)) { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } ctx.write(response); //通过Netty的ChunkedFile将文件直接写入到发送缓冲区 ChannelFuture sendFileFeature; sendFileFeature= ctx.write(new ChunkedFile(randomAccessFile, 0, fileLength, 8192), ctx.newProgressivePromise()); //添加GenericProgressiveFutureListener,如果发送完成打印 System.out.println("Transfer complete"); sendFileFeature.addListener(new ChannelProgressiveFutureListener() { // public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) throws Exception { if (total < 0) { System.err.println("Transfer progress:" + progress); } else { System.err.println("Transfer progress:" + progress + "/" + total); } } public void operationComplete(ChannelProgressiveFuture future) throws Exception { System.out.println("Transfer complete"); } }); //发送一个EMPTY_LAST_CONTENT说明完成 ChannelFuture lastContentFuture = ctx .writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); if (!isKeepAlive(request)) { lastContentFuture.addListener(ChannelFutureListener.CLOSE); } } private void setContentTypeHeader(HttpResponse response, File file) { MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap(); response.headers().set(CONTENT_TYPE, mimetypesFileTypeMap.getContentType(file.getPath())); } /** * 构造错误信息 * * @param ch * @param status */ private void sendError(ChannelHandlerContext ch, HttpResponseStatus status) { FullHttpResponse response = new DefaultFullHttpResponse( HTTP_1_1, status, Unpooled.copiedBuffer("Faile: " + status.toString() + "\r\n", CharsetUtil.UTF_8)); // response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); ch.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } /** * 加工url * @param uri * @return */ private String sanitizeUri(String uri) { //先用UTF-8解码,如果失败了在用ISO-8859-1 try { uri = URLDecoder.decode(uri, "UTF-8"); } catch (UnsupportedEncodingException e) { try { uri = URLDecoder.decode(uri, "ISO-8859-1"); } catch (UnsupportedEncodingException e1) { throw new Error(); } } //如果不是符合规范的请求,则拒绝 if (!uri.startsWith(url) || !uri.startsWith("/")) { return null; } uri = uri.replace('/', File.separatorChar); // if (uri.contains(File.separator + '.') || uri.contains('.' + File.separator) || uri.startsWith(".") || uri.endsWith(".") || INSECURE_URI.matcher(uri).matches()) { return null; } return System.getProperty("user.dir") + File.separator + uri; } /** * 构造显示的列表信息 * @param context * @param dir */ private void sendListing(ChannelHandlerContext context, File dir) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK); //创建成功的http相应消息,使用text/html便于直接显示再浏览器上 response.headers().set(CONTENT_TYPE, "text/html;charset=UTF-8"); StringBuilder builder = new StringBuilder(); String dirPath = dir.getPath(); //拼接HTML builder.append("<!DOCTYPE html>\r\n"); builder.append("<html><head><title>"); builder.append(dirPath); builder.append("目录:"); builder.append("</title></head><body>\r\n"); builder.append("<h3>"); builder.append(dirPath).append(" 目录: "); builder.append("</h3>\r\n"); builder.append("<ul>"); builder.append("<li>链接:<a href=\"../\">..</a></li>\r\n"); //构造列表 for (File file : dir.listFiles()) { if (file.isHidden() || !file.canRead()) { continue; } //过滤文件名 String fileName = file.getName(); if (!ALLOWED_FILE_NAME.matcher(fileName).matches()) { continue; } //超链接 builder.append("<li>链接: <a href=\" "); builder.append(fileName); builder.append("\">"); builder.append(fileName); builder.append("</a></li>\r\n"); } builder.append("</ul></body></html>\r\n"); //万能的ByteBuf ByteBuf byteBuf = Unpooled.copiedBuffer(builder, CharsetUtil.UTF_8); response.content().writeBytes(byteBuf); //释放缓存区 byteBuf.release(); context.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } /** * 从定向 * * @param context * @param newUri */ private void sendRedirect(ChannelHandlerContext context, String newUri) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, FOUND); response.headers().set(LOCATION, newUri); context.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } public void exceptionCaught(ChannelHandlerContext context,Throwable cause){ cause.printStackTrace(); if(context.channel().isActive()){ sendError(context,INTERNAL_SERVER_ERROR); } }}
阅读全文
0 0
- 6、netty http协议开发应用(netty学习笔记)
- Netty之http协议开发
- Netty之HTTP协议开发
- Netty的HTTP协议开发
- 8.netty开发http协议
- Netty学习笔记3: 私有协议栈开发
- Netty Http协议栈开发(客户端&服务端)
- 9.netty开发http+xml协议栈
- 【Netty】netty学习笔记一
- Netty自定义协议开发
- netty 私有协议开发
- Netty 协议开发
- netty权威指南 学习笔记http
- 开发Netty应用
- Netty入门应用开发
- Netty源码学习笔记
- Netty学习笔记一
- Netty 学习笔记
- kafka入门:简介、使用场景、设计原理、主要配置及集群搭建(转)
- android中WiFi wps连接方式
- python 画图 例子
- [Swift 开发] GCD常用方法
- PAT 甲级 1038. Recover the Smallest Number (30)
- 6、netty http协议开发应用(netty学习笔记)
- AOP创建切面
- 搜索树的建立,高度的获得,最大值的获得
- 实用小技巧
- Qt注意事项(2)
- Java学习笔记(17)-- 值传递与引用传递
- 欢迎使用CSDN-markdown编辑器
- MFC 右键系统菜单
- 关于循环删除集合中的元素