美文网首页netty学习Netty实践我爱编程
netty同时做HTTP和websocket服务器并且实现HTT

netty同时做HTTP和websocket服务器并且实现HTT

作者: jcala | 来源:发表于2016-06-03 11:04 被阅读7618次

    博客 Github

    近期需要给别人做一个HTTP加Websocket的处理后端,果断选了spring+netty的组合,spring提供IOC容器+AOP+事务,netty处理IO,但是netty提供的HTTP比较底层,还需要自己处理路由,,,还是比Servlet麻烦不少,于是陆续将自己学习和编码过程中一些东西写出来,希望能帮的到别人。用的是netty5


    学习netty用到的资源
    1. 官网的API文档
    2. 《netty权威指南》,给很多步骤做出了解释,没解释的看API
    3. 官方的demo,下载netty-example-5.0.0.Alpha2-sources.jar源码包解压,给出了很多Demo
    4. 博客1 博客2 还有很多
    5. Github,netty项目很多,分析下源码
    server端编码,主要讲一下channel中的handler
    1. HttpServerCodec:ByteBuf->HttpRequest或HttpContent和HttpResponse或者HttpContent->ByteBuf,即HTTP请求的解码和编码
    2. HttpObjectAggregator:把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse,原因是HTTP解码器会在每个HTTP消息中生成多个消息对象HttpRequest/HttpResponse,HttpContent,LastHttpContent
    3. WebSocketServerCompressionHandler:WebSocket数据压缩(可选)
    4. ChunkedWriteHandler:大文件支持(没有写在代码中,可选)
    5. HttpHandler:自定义的HTTP和Websocket处理类,二者处理也可以分开在多个ChannelHandler中,在这里写在一个Handler中
      • handler方法和childHandler方法区别
        • handler存在于AbstractBootstrap,目的是添加一个handler,监听Bootstrap动作,它在初始化时就会执行
        • childHandler存在于ServerBootstrap,目的是添加一个handler,监听已经连接的客户端的Channel的动作和状态,在客户端连接成功后才执行。
      • option方法和childOption方法区别
        • option存在于AbstractBootstrap,提供给NioServerSocketChannel用来接收进入的连接。
        • childOption存在于ServerBootstrap ,提供给ServerChannel接收已经建立的连接。
     public void run(final int port) throws InterruptedException {
            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("respDecoder-reqEncoder",
                                        new HttpServerCodec())
                                        .addLast("http-aggregator",
                                                new HttpObjectAggregator(65536))
                                        .addLast(new WebSocketServerCompressionHandler())
                                        .addLast("action-handler", new HttpHandler());
                            }
                        });
                ChannelFuture future = b.bind(new InetSocketAddress(port)).sync();
                logger.info("The http server powered by netty is listening on " + port);
                future.channel().closeFuture().sync();//阻塞处理,等待服务端链路关闭之后main函数才退出
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    
    自定义的ChannelHandler,用于处理HTTP和Websocket
    1. 区别HTTP和Websocket请求

       @Override
      public void messageReceived(ChannelHandlerContext ctx, Object msg) {
          if (msg instanceof FullHttpRequest) {//如果是HTTP请求,进行HTTP操作
              handleHttpRequest(ctx, (FullHttpRequest) msg);
          } else if (msg instanceof WebSocketFrame) {//如果是Websocket请求,则进行websocket操作
              handleWebSocketFrame(ctx, (WebSocketFrame) msg);
          }
      }
      

      上面的Object类型的msg就是extends SimpleChannelInboundHandler<Object>中的Object,我们可以定义ChannelHandler时将Object换成FullHttpRequest,这样就只处理HTTP请求,换成WebSocketFrame只处理websocket

    2. HTTP请求的分发

      //处理HTTP的代码
       private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
           HttpMethod method=req.method();
           String uri=req.uri();
           diapathcer(method,uri);
       }
      private void diapathcer(HttpMethod method,String uri){
           if(method==HttpMethod.GET&&"/login".equals(uri)){
               //....处理
           }else if(method==HttpMethod.POST&&"/register".equals(uri)){
               //...处理
           }
      
       }
      
    3. 实际中路由不会这样写,我们可以自定义路由的实现,写在一个类中专门实现路由,或者自定义一个配置文件,像properties一样,每一行格式形如:(GET  \login LoginAction),我们知道properties是继承HashTable(String,String),我们可以自定义配置文件的对应类继承HashMap(String,HashMap(String,String)),我自己已经将路由和路由配置文件的实现完成,以后会陆续公开
    4. 自定义ChannelHandler代码
    ```java
    public class HttpHandler extends SimpleChannelInboundHandler<Object> {
      @Override
      public void messageReceived(ChannelHandlerContext ctx, Object msg) {
          if (msg instanceof FullHttpRequest) {//如果是HTTP请求,进行HTTP操作
              handleHttpRequest(ctx, (FullHttpRequest) msg);
          } else if (msg instanceof WebSocketFrame) {//如果是Websocket请求,则进行websocket操作
              handleWebSocketFrame(ctx, (WebSocketFrame) msg);
          }
      }
      @Override
      public void channelReadComplete(ChannelHandlerContext ctx) {
          ctx.flush();
      }
      //处理HTTP的代码
      private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
          HttpMethod method=req.method();
          String uri=req.uri();
          diapathcer(method,uri);
      }
      private void diapathcer(HttpMethod method,String uri){
          if(method==HttpMethod.GET&&"/login".equals(uri)){
              //....处理
          }else if(method==HttpMethod.POST&&"/register".equals(uri)){
              //...处理
          }
    
      }
      //处理Websocket的代码
      private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
      }
      @Override
      public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
          cause.printStackTrace();
          ctx.close();
      }
    }
    

    相关文章

      网友评论

      • beyondxurui:可以公开看吗
      • ff95ecf9ee5c:请问用netty可以代理访问https的站点吗?
      • 独钓寒雪1795:有没有同时做http和socket的服务
      • Prettyxbb:已读,写的挺好的,刚刚开始学习这个,收获很大,不过我还是有很多不懂得,加油

      本文标题:netty同时做HTTP和websocket服务器并且实现HTT

      本文链接:https://www.haomeiwen.com/subject/lonkdttx.html