Netty Crash Course

一个Netty程序一般开始于Bootstrap类,通过设置程序后,使用Handlers来处理特定的event和设置Netty中的事件,从而处理多个协议数据,比如实现ChannelInBoundHandler类;

多个Handler通过ChannelInitializer的ChannelPipeline组合在一起,再配合EventLoop(整个生命周期内绑定对应一条线程)和EventLoopGroup来处理各种业务逻辑。

Channels, Events and Input/Ouput

Netty中所有操作都是异步执行的,例如连接一个主机、发消息。可以注册监听器来通知,如Futures(注册一个监听,当操作成功或者失败时会通知)和ChannelFutures(封装的是一个操作的相关信息,操作被执行会理科返回ChannelFuture)。

Bootstrap

两种引导,用于客户端或者DatagramChannel的Bootstrap(一个EventGroup)和用于服务端的ServerBootstrap(两个EventGroup)。

EventLoopGroup可以包含很多个EventLoop,每个channel绑定一个EventLoop不会被改变,很多channel共享一个EventLoop。这就意味着如果一个Channel保持EventLoop繁忙,会禁止其他channel绑定到相同的EventLoop,我们可以理解EventLoop为一个事件循环线程,而EventLoop是一个事件循环集合。

Channel Handler and Data Flow

Handlers自身依赖ChannelPipeline来决定它们的执行顺序。

ChannelHandler定义了一个父接口,ChannelInboundHandler(入站,读)和ChannelOutboundHandler(出站,写)是其子接口,ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter是桥接器类。

入站是从ChannelPipeline的头部开始传递到最后,而出站是从尾部开始。

Netty发消息有两种方法:1、直接写入通道导致消息从ChannelPipeline的尾部开始;2、写入ChannelHandlerContext对象导致处理消息从ChannelPipeline的下一个handler开始

编码器、解码器和业务逻辑

每个Handler负责转发时间到ChannelPipeline的下一个handler,但在*Adapter(和子类)中是自动完成的:

ChannelHandlerAdapter,ChannelInboundHandlerAdapter,ChannelOutboundHandlerAdapter,

ByteToMessageDecoder,MessageToByteEncoder,ProtobufEncoder,ProtobufDecoder

所有的解码器都继承或者实现ChannelInboundHandlerAdapter或者ChannelInboundHandler,channelRead放大调用decode方法,并通过ChannelHandlerContext.fireChannelRead(Object msg)传递给下一个handler。编码器类似。

也许最常见的应用程序处理接收到消息后进行解码,然后供相应的业务处理模块使用。那么有用程序只需要拓展SimpleChannelInboundHandler<T>,SimpleChannelOutboundHandler<T>即可。主要方法是channelRead0(ChannelHadnlerContext ctx, T msg); 消费msg时需要注意,Netty中梳理IO一般有很多线程,不要阻塞IO线程,因为阻塞会降低程序的性能,解决方案是添加ChannelHandler到ChannelPipeline时指定一个EventExecutorGroup,EventExecutorGroup会获得一个EventExecutor,EventExecutor将会执行ChannelHandler的所有方法:

double coefficient = 0.8;  //系数
int numberOfCores = Runtime.getRuntime().availableProcessors();
int poolSize = (int)(numberOfCores / (1 - coefficient));
static final EventExecutorGroup group = new DefaultEventExecutorGroup(poolSize); ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("encoder", new MyProtocolEncoder());
// Tell the pipeline to run MyBusinessLogicHandler's event handler methods
// in a different thread than an I/O thread so that the I/O thread is not blocked by
// a time-consuming task.
// If your business logic is fully asynchronous or finished very quickly, you don't
// need to specify a group.
pipeline.addLast(group, "handler", new MyBusinessLogicHandler());

如需要定时执行简单的任务,可以使用EventLoop:

ch.eventLoop().schedule(...);
或者
ScheduleFuture f = ch.eventLoop().scheduleAtFixedRate(...);
f.cancel(true);

Netty使用reference-counting来安全释放Buf和其他资源:

ByteBuf

字节数据容器,单独维护读写两个索引,最大容量限制是Integer.MAX_VALUE,三种不同类型的ByteBuf:

1、Heap Buffer(堆缓冲区)

数据存储在JVM的堆空间中,通过数组实现,可以使用ByteBuf的array()来获取数据。访问非堆缓冲区的ByteBuf的数组会导致UNsupportedOperationException,可以使用hasArray()来检查

2、Direct Buffer(直接缓冲区)

堆之外直接分配内存,性能很好,分配和释放比较复杂,使用内存池来解决。不支持直接数组访问数据:

ByteBuf buf = Unpooled.directBuffer(16);
if (!buf.hasArray()) {
int len = buf.readableBytes();
byte[] arr = new byte[len];
buf.getBytes(arr);
}

3、Composite Buffer(复合缓冲区)

提供一个视图组合多个buff,hasArray()总返回false。

CompositeByteBuf cbf = Unpooled.compositeBuffer();
ByteBuf heap = Unpooled.buffer(8);
ByteBuf direct = Unpooled.directBuffer(16);
cbf.addComponents(heap, direct); cbf.removeComponent(0); Iterator<ByteBuf> iter = cbf.iterator();
while(iter.hasNext()) {
System.out.println(iter.next().toString());
} if (!cbf.hasArray()) {
int len = cbf.readableBytes();
byte[] arr = new byte[len];
cbf.getBytes(0, arr);
}

相关方法:

isReadable()是否还可以继续读

writeableBytes()剩余可写空间

clear()重置读写的index为0

discardReadBytes()清空已读数据,会移动字节位置,设计到内存复制,注意性能问题

readerIndex(int idx)设置读索引位置

writerIndex(int idx)设置写索引位置

duplicate()、slice()、slice(int index, int length)、order(ByteOrder endianness)这些会创建缓冲区视图但有独立的读写索引

copy()或者copy(int index, int length)创建全新的副本

ByteBufProcessor

搜索操作,如bytesBefore(byte value)

ByteBufHolder

帮助更快捷的访问ByteBuf中的数据,当缓冲区没用了之后,尅只用这个辅助类释放资源。

ByteBufAllocator

负责分配ByteBuf实例,可以从Channel或者ChannelHandlerContext的alloc()方法获得该对象,有两种实现,一为将分配和回收成本以及内存使用降到最低,另一种是每次使用都创建新的ByteBuf实例。

Netty默认使用PooledByteBufAllocator,可以通过ChannelConfig或者引导设置不同的实现来改变。

Unpooled

创建缓冲区的工具类。

ByteBufUtil

工具类,hexDump(ByteBuf buff)

Netty入门(2) - 核心概念的更多相关文章

  1. ElasticSearch入门及核心概念介绍

      Elasticsearch研究有一段时间了,现特将Elasticsearch相关核心知识和原理以初学者的角度记录下来,如有不当,烦请指正! 0. 带着问题上路——ES是如何产生的? (1)思考:大 ...

  2. zookerper入门、核心概念和使用场景

    zookeeper是一个分布式程序的高性能协调服务,提供集中式信息存储服务,数据存储于内存中,类似文件系统的树形结构,高吞吐量和低延时,集群高可靠,基于zookeeper可以实现分布式统一配置中心.分 ...

  3. JAVAEE——BOS物流项目13:Quartz入门案例、核心概念、cron 表达式的格式(了解)

    1.quartz入门案例 本入门案例基于spring和quartz整合完成. 第一步:创建maven工程,导入spring和quartz相关依赖 第二步:创建任务类 第三步:在spring配置文件中配 ...

  4. lucene 核心概念及入门

    lucene Lucene介绍及核心概念 什么是Lucene Lucene是一套用于全文检索和搜索的开放源代码程序库,由Apache软件基金会支持和提供.Lucene提供了一个简单却强大的应用程序接口 ...

  5. Elasticsearch入门教程(二):Elasticsearch核心概念

    原文:Elasticsearch入门教程(二):Elasticsearch核心概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:ht ...

  6. JAVA入门(1.JAVA平台应用 2.核心概念:JVM,JDK,JRE 3.搭建JAVA开发环境 4.学习JAVA的原则)

    主要内容: 1.JAVA平台应用 2.核心概念:JVM,JDK,JRE 3.搭建JAVA开发环境 4.学习JAVA的原则 JAVA的平台应用 JAVA的平台应用分为3个部分: 一.JAVA SE,主要 ...

  7. Mycat入门核心概念

      Mycat中的核心概念     Mycat中的核心概念 1.数据库中间件    Mycat 是一个开源的分布式数据库系统,但是由于真正的数据库需要存储引擎,而 Mycat 并没有 存储引擎,所以并 ...

  8. Netty核心概念(4)之Bootstrap

    1.前言 第三节介绍了Netty的一些基本概念,此节介绍Netty的第一个概念Bootstrap——启动类.Netty中服务端和客户端的启动类是不一样的,这个不要搞错了,类都在bootstrap包下. ...

  9. 从零开始入门 K8s| 阿里技术专家详解 K8s 核心概念

    作者| 阿里巴巴资深技术专家.CNCF 9个 TCO 之一 李响 一.什么是 Kubernetes Kubernetes,从官方网站上可以看到,它是一个工业级的容器编排平台.Kubernetes 这个 ...

随机推荐

  1. Highcharts之折线图

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. MyBatis学习(七)MyBatis关联映射之多对多映射

    对于数据库中的多对多关系建议使用一个中间表来维护关系. 1.创建四张表,分别为用户表,商品表,订单表,中间表. DROP TABLE IF EXISTS `t_user`; CREATE TABLE ...

  3. BZOJ1212[HNOI2004]L语言——trie树+DP

    题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...

  4. BZOJ5294 [BJOI2018] 二进制 【线段树】

    BJOI的题目感觉有点难写 题目分析: 首先推一波结论.接下来的一切都在模3意义下 现在我们将二进制位重组,不难发现的是2^0≡1,2^1≡2,2^2≡1,2^3≡2....所以我们考虑这样的式子 2 ...

  5. jQuery添加和删除元素

    添加新的 HTML 内容 我们将学习用于添加新内容的四个 jQuery 方法: append() - 在被选元素的结尾插入内容 prepend() - 在被选元素的开头插入内容 after() - 在 ...

  6. 洛谷P1973 [NOI2011]Noi嘉年华(动态规划,决策单调性)

    洛谷题目传送门 DP题怕是都要大大的脑洞...... 首先,时间那么大没用,直接离散化. 第一问还好.根据题意容易发现,当一堆活动的时间有大量重叠的时候,更好的办法是把它们全部安排到一边去.那么我们转 ...

  7. Python的单向链表实现

    思路 链表由节点组成,先规定节点(Node),包含data和指向下个节点的next 初始化 data当然就是传入的data了,next指向None 添加 分两种情况: 链表为空,那么头节点和尾节点都指 ...

  8. selenium 登陆小技巧

    from selenium import webdriver from selenium.webdriver.common.keys import Keys driver = webdriver.Fi ...

  9. java反射出字段信息和值

    /** * */ package test; import java.lang.reflect.Field; import java.lang.reflect.Modifier; /** * @aut ...

  10. 洛谷P4112 最短不公共子串

    题意: 下面,给两个小写字母串A,B,请你计算: (1) A的一个最短的子串,它不是B的子串 (2) A的一个最短的子串,它不是B的子序列 (3) A的一个最短的子序列,它不是B的子串 (4) A的一 ...