Netty

作者: 请叫我平爷 | 来源:发表于2022-02-18 08:52 被阅读0次

    Netty组件

    • I/O:流的处理(输入输出)
    • Channel:通道,代表一个请求,每个Client都对应一个Channel
    • ChannelHandler:用于处理业务请求
    • ChannelHandlerContext:用于传输业务数据
    • ChannelPipeline:责任链,每个Channel都有有且仅有一个ChannelPipeline,里面有各种Handler,用于保存处理过程需要用到的ChannelHandler和ChannelHandlerContext。
    • handler:处理入站消息以及相应的事件
    • EventLoopGroup:I/O线程池,处理对应Channel对应的I/O事件
    • ServerBootstrap:服务器端启动辅助对象
    • Bootstrap:客户端启动辅助对象
    • ChannelInitalizer:Channel初始化器
    • ChannelFuture:I/O操作的执行结果,通过事件机制,获得机制结果,通过添加监听器,执行我们想要的操作
    • ByteBuf:字节序列,通过ByteBuf操作基础的字节数组和缓冲区,使用方便
      • Heap Buffer 堆缓冲区:最常用
      • Direct Buffer 直接缓冲区:内存分配不在堆,
      • Composite Buffer 复合缓冲区:

    引入Netty包

    <dependency> 
        <groupId>io.netty</groupId> 
        <artifactId>netty-all</artifactId> 
        <version>4.1.73.Final</version> 
    </dependency> 
    <dependency>
       <groupId>com.alibaba</groupId>
       <artifactId>fastjson</artifactId>
       <version>1.2.70</version> 
    </dependency>
    

    Netty写一个Server服务器

    NettyHttpServer

    public class NettyHttpServer { 
      private int port; 
      public NettyHttpServer(int port) { 
          this.port = port; 
      } 
      public void run() throws Exception { 
      //处理I/O操作多线程事件循环器,boss收到连接,分配到worker上 
          EventLoopGroup bossGroup = new NioEventLoopGroup(); 
          EventLoopGroup workerGroup = new NioEventLoopGroup(); 
          try { 
              ServerBootstrap b = new ServerBootstrap();//启动NIO服务的辅助启动类,用于服务通道的一系列配置 
              b.group(bossGroup, workerGroup)//绑定两个线程组 
                .channel(NioServerSocketChannel.class) // 制定NIO模式 
                .childHandler(new ChannelInitializer<SocketChannel>() { 
                          @Override protected void initChannel(SocketChannel socketChannel) throws Exception {
                                     ChannelPipeline pipeline = socketChannel.pipeline(); 
                                     pipeline.addLast(new HttpServerCodec());// http 编解码 
                                     pipeline.addLast("httpAggregator",new HttpObjectAggregator(512*1024)); // http 消息聚合器 512*1024为接收的最大contentlength 
                                     pipeline.addLast(new NettyHttpServerHandler());// 请求处理器 
                          } }); 
               ChannelFuture f = b.bind(port).sync(); // 绑定端口 
               f.channel().closeFuture().sync(); 
            } 
            finally { 
                    workerGroup.shutdownGracefully(); 
                    bossGroup.shutdownGracefully(); 
            } 
      } 
      public static void main(String[] args) throws Exception { 
          new NettyHttpServer(8080).run(); 
      } 
    }
    

    handler

    public class NettyHttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> { 
          @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) throws Exception { 
              // 获取请求的uri 
              String uri = fullHttpRequest.uri(); 
              Map<String,String> resMap = new HashMap<>(); 
              resMap.put("method",fullHttpRequest.method().name()); 
              resMap.put("uri",uri); String msg = JSON.toJSONString(resMap); 
              System.out.println("resMap:"+JSON.toJSONString(fullHttpRequest)); 
              // 创建http响应 FullHttpResponse    
              response = new DefaultFullHttpResponse( HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8)); 
              // 设置头信息 
              response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8"); 
              // 将html write到客户端 
              channelHandlerContext.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); 
        }
    }
    

    访问
    http://localhost:8080/getName?name=123

    优点:

    1. 并发高:
      基于NIO,当一个Socket建立好连接后,Thread并将请求交给Selector,Selector不断遍历所有的Socket,一旦Socket建立完成,会通知Thread,然后Thread处理完再返回客户端,这个是过程不阻塞的,一个Thread可以处理更多的请求。

    2. 传输快:

    • 零拷贝,再堆内存之外开辟一块内存,数据直接从IO读到那块内存中去,netty通过ByteBuf直接对这些数据进行操作,从而加快传输速度
    • 封装好:
    • 代码量少

    粘包/拆包

    • TCP粘包、拆包问题:

      • TCP是一个流协议,没有分界线
      • TCP并不知道上层业务数据的具体含义,根据TCP缓冲区的具体情况进行包的划分,在业务上一个完整的包可能会被TCP分成多个包进行发送,也可能把多个小包封装成一个大的数据包发送出去,这就是所谓的粘包/拆包问题
    • 解决:

      1. 消息定长:例如每个报文大小固定200字节,不够空格补
      2. 尾部加特殊字符,如回车
      3. 将消息分为消息头和消息体,消息头中包含消息总长度字段
    • Netty解决方法:

      1. 分隔符:DelimiterBasedFrameDecoder
      2. 定长:FixedLengthFrameDecoder

    相关文章

      网友评论

          本文标题:Netty

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