文档章节

基于Netty的http服务器

zhdan
 zhdan
发布于 2016/03/28 23:56
字数 785
阅读 106
收藏 4

根据netty一个官方例子改编

 

//html文件位置
public class Config {
    public static String getRealPath(String uri) {
        StringBuilder sb=new StringBuilder("E:/htmlDemo");
        sb.append(uri);
        if (!uri.endsWith("/")) {
            sb.append('/');
        }
        return sb.toString();
    }
}
//根据url获取html资源
public class HttpServerHandler2  extends SimpleChannelInboundHandler<Object> {
 private HttpRequest request;
 private boolean readingChunks; 
 private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //Disk
   
    private HttpPostRequestDecoder decoder;
 
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (decoder != null) {
            decoder.cleanFiles();
        }
    }
    
 @Override
 public void channelReadComplete(ChannelHandlerContext ctx){
  ctx.flush();
  System.out.println("channelReadComplete");
 }
 
 
 @Override
 protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
  if (msg instanceof HttpRequest) {
            HttpRequest request = this.request = (HttpRequest) msg;
            
            if (HttpHeaderUtil.is100ContinueExpected(request)) {
                send100Continue(ctx);
            }
            HttpHeaders headers = request.headers();
            if (!headers.isEmpty()) {
                for (Map.Entry<CharSequence, CharSequence> h: headers) {
                    CharSequence key = h.getKey();
                    CharSequence value = h.getValue();
                    
                }
              
            }
            QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri());
            Map<String, List<String>> params = queryStringDecoder.parameters();
            if (!params.isEmpty()) {
                for (Entry<String, List<String>> p: params.entrySet()) {
                    String key = p.getKey();
                    List<String> vals = p.getValue();
                    for (String val : vals) {
                       
                    }
                }
                
            }
            try {
                decoder = new HttpPostRequestDecoder(factory, request);
            } catch (ErrorDataDecoderException e1) {
                e1.printStackTrace();
                //writeResponse(ctx.channel());
                ctx.channel().close();
                return;
            }
            readingChunks = HttpHeaderUtil.isTransferEncodingChunked(request);
            System.out.println("Is Chunked: " + readingChunks + "\r\n");
            System.out.println("IsMultipart: " + decoder.isMultipart() + "\r\n");
            if (readingChunks) {
                // Chunk version
             System.out.println("Chunks: ");
                readingChunks = true;
            }
        }
  if(decoder != null){
   if (msg instanceof HttpContent) {
     // New chunk is received
                HttpContent chunk = (HttpContent) msg;
                try {
                    decoder.offer(chunk);
                } catch (ErrorDataDecoderException e1) {
                    e1.printStackTrace();
                    //writeResponse(ctx.channel());
                    ctx.channel().close();
                    return;
                }
                System.out.println('o');
                
                //readHttpDataChunkByChunk();
                // example of reading only if at the end
                if (chunk instanceof LastHttpContent) {
                 String uri = this.request.uri();
                    System.out.println("-----------------------------------------------------------------");
                    System.out.println("uri:"+uri);
                    System.out.println("-----------------------------------------------------------------");
                   
                    writeResponse(ctx, uri);
                    readingChunks = false;
                    reset();
                }
         }
  }else {
            writeResponse(ctx, "/");
        }
               
    }
 
 
  private void reset() {
         request = null;
         // destroy the decoder to release all resources
         decoder.destroy();
         decoder = null;
  }
 private void writeResponse(ChannelHandlerContext ctx, String uri) {
        // 解析Connection首部,判断是否为持久连接
        boolean keepAlive = HttpHeaderUtil.isKeepAlive(request);
 
        // Build the response object.
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
        response.setStatus(HttpResponseStatus.OK);
        // 服务端可以通过location首部将客户端导向某个资源的地址。
        // response.addHeader("Location", uri);
        if (keepAlive) {
            // Add 'Content-Length' header only for a keep-alive connection.
            response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
        }
        // 得到客户端的cookie信息,并再次写到客户端
        String cookieString = request.headers().getAndConvert(HttpHeaderNames.COOKIE);
        if (cookieString != null) {
            Set<Cookie> cookies = ServerCookieDecoder.decode(cookieString);
            if (!cookies.isEmpty()) {
                // Reset the cookies if necessary.
                for (Cookie cookie: cookies) {
                    response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.encode(cookie));
                }
            }
        } else {
            // Browser sent no cookie.  Add some.
            response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.encode("key1", "value1"));
            response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.encode("key2", "value2"));
        }
        
        //文件路径
        final String path = (Config.getRealPath(uri));
        File localFile = new File(path);        
        // 如果文件隐藏或者不存在
        if (localFile.isHidden() || !localFile.exists()) {
            // 逻辑处理
         System.out.println("如果文件隐藏或者不存在");
         sendError(ctx, NOT_FOUND);
            return;
        }
        // 如果请求路径为目录
        if (localFile.isDirectory()) {
            // 逻辑处理
         System.out.println("如果请求路径为目录");
            return;
        }
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(localFile, "r");
            long fileLength = raf.length();            
            response.headers().setLong(HttpHeaderNames.CONTENT_LENGTH, fileLength);
            Channel ch = ctx.channel();
            ch.write(response);
            // 这里又要重新温习下http的方法,head方法与get方法类似,但是服务器在响应中只返回首部,不会返回实体的主体部分
            if (!request.method().equals(HttpMethod.HEAD)) {
             System.out.println("读文件");
                ch.write(new ChunkedFile(raf, 0, fileLength, 8192));//8kb
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        } finally {
            if (keepAlive) {
              response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
            }
            if (!keepAlive) {
                ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
            }
        } 
    }
 
 private void send100Continue(ChannelHandlerContext ctx) {
  FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
  ctx.write(response);
 }
 @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
 
 private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
  FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status,
    Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
  response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
  ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
 } 
}

 

 

 
//服务运行类
public class HttpServer {

    public void run(final int port) throws Exception {
 EventLoopGroup bossGroup = new NioEventLoopGroup();
 EventLoopGroup workerGroup = new NioEventLoopGroup();
 try {
     ServerBootstrap b = new ServerBootstrap();
     b.group(bossGroup, workerGroup)
      .channel(NioServerSocketChannel.class)
      .childHandler(new ChannelInitializer<SocketChannel>() {
   @Override
   protected void initChannel(SocketChannel ch)
    throws Exception {
       ch.pipeline().addLast("http-decoder",
        new HttpRequestDecoder());
       ch.pipeline().addLast("http-aggregator",
        new HttpObjectAggregator(65536));
       ch.pipeline().addLast("http-encoder",
        new HttpResponseEncoder());
       ch.pipeline().addLast("http-chunked",
        new ChunkedWriteHandler());
       ch.pipeline().addLast("handler",
        new HttpServerHandler());
   }
      });
     ChannelFuture future = b.bind("192.168.1.10", port).sync();
     System.out.println("HTTP服务器启动,网址是 : " + "http://192.168.1.10:"
      + port);
     future.channel().closeFuture().sync();
 } finally {
     bossGroup.shutdownGracefully();
     workerGroup.shutdownGracefully();
 }
    }
    public static void main(String[] args) throws Exception {
 
     new HttpServer().run(8080);
    }

 

© 著作权归作者所有

共有 人打赏支持
zhdan
粉丝 5
博文 34
码字总数 13824
作品 0
深圳
私信 提问
高性能网络应用框架--Netty

Netty是一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基于NIO的客户、服务器端编...

匿名
2008/09/23
102.3K
16
第八章:附带的ChannelHandler和Codec

本章介绍 使用SSL/TLS创建安全的Netty程序 使用Netty创建HTTP/HTTPS程序 处理空闲连接和超时 解码分隔符和基于长度的协议 写大数据 序列化数据 上一章讲解了如何创建自己的编解码器,我们现在...

李矮矮
2016/09/26
90
0
如何使用Netty开发实现高性能的RPC服务器

RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络,从远程计算机程序上请求服务,而不必了解底层网络技术的协议。说的再直白一点,就是客户端在不必知道调用细节的...

vshcxl
2017/10/20
0
0
基于Netty的Http应用服务器 --loServer

loServer 基于Netty的Http应用服务器 介绍 在之前公司的时候有一些小任务是这样的:写一个小Http接口处理一些任务(这个任务常常只需要几行代码)。然后我就开始写个简单的Servlet,挂在Tom...

路小磊
2015/07/16
1K
0
SLG手游Java服务器的设计与开发——网络通信

前言 上文分析了我们这款SLG的架构,本章着重讲解我们的网络通信架构,由上文的功能分析我们可以得知,游戏的所有功能基本上属于非及时的通信机制,所以依靠HTTP短连接就能够基本满足游戏的通...

umgsai
2016/09/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

table边框样式

table{ border:0.5px solid #000; border-collapse:collapse; //去除边框间空隙}th,td{ border:0.5px solid #000;}...

学霸猫
18分钟前
1
0
分布式消息通讯Kafka原理分析(二)

本章重点: 1.消息的存储原理2.Partition的副本机制原理3.副本数据同步原理 消息的文件存储机制 通过如 下命令找到对应partition下的日志内容 [root@localhost ~]# ls /tmp/kafka-logs/f...

须臾之余
23分钟前
1
0
Vue Element表单绑定(四)常用操作整理

一、启用回车提交报单操作 在登录页面,使用回车提交表单操作一般是必要的一个操作。在 Element中如何使用呢,示例如下: 来个注意点: 1.button按钮的native-type设置为submit,而不是绑定c...

tianma3798
27分钟前
1
0
《大话数据结构》读后总结(七)

常见的时间复杂度 执行次数 函数阶 非正式术语 12 O(1) 常数阶 2n+3 O(n) 线性阶 3n^2+2n+1 O(n2) 平方阶 5log2n+20 O(logn) 对数阶 2n+3nlog2n+19 O(nlogn) nlogn阶 6n^3+2n^2+3n+4 O(n3) 立...

徐曙辉
29分钟前
0
0
three.js 事件交互

点击查看交互效果 在three.js中,展示的一切内容都是在canvas中绘制的,所以点击事件点击到物体上是无法获取点击对象的,要获取点击的对象要使用RayCaster,用于在三维空间中进行鼠标拾取,原...

tianyawhl
29分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部