[TOC]
1. Netty 在內部使用了回調來處理事件;當一個回調被觸發時,相關的事件可以被一個 interfaceChannelHandler 的實現處理。當一個新的連接已經被建立時,ChannelHandler 的 channelActive()回調方法將會被調用,并將打印出一條信息。
2. 所有的 Netty 服務器都需要以下兩部分。
* 至少一個 ChannelHandler—該組件實現了服務器對從客戶端接收的數據的處理,即
它的業務邏輯。
* 引導—這是配置服務器的啟動代碼。至少,它會將服務器綁定到它要監聽連接請求的
端口上。
在本小節的剩下部分,我們將描述 Echo 服務器的業務邏輯以及引導代碼。
3. 每個 Channel 都擁有一個與之相關聯的 **ChannelPipeline**,其持有一個 ChannelHandler 的實例鏈。也就是說一個pipeline上有多個channel,這些channel是串聯起來的,并且上一個channel的結果會傳遞到下一個channel。

:-: 圖一
## 1. 引導(Bootstrap)
### 1.1 ServerBootstrap
服務端啟動引導類,設置netty服務端啟動參數
兩種類型的引導:
> 1. 一種用于客戶端(簡單地稱為 Bootstrap)
> 2. 而另一種( ServerBootstrap)用于服務器。
>
## 2. EventLoopGroup
EventLoop 定義了 Netty 的核心抽象, 用于處理連接的生命周期中所發生的事件。

:-: 圖二
1. 一個 EventLoopGroup 包含一個或者多個 EventLoop;
2. 一個 EventLoop 在它的生命周期內只和一個 Thread 綁定;
3. 所有由 EventLoop 處理的 I/O 事件都將在它專有的 Thread 上被處理;
4. 一個 Channel 在它的生命周期內只注冊于一個 EventLoop;
5. 一個 EventLoop 可能會被分配給一個或多個 Channel。
注意,在這種設計中, 一個給定 Channel 的 I/O 操作都是由相同的 Thread 執行的, 實際上消除了對于同步的需要。
## 1. channel
基本的 I/O 操作( bind()、 connect()、 read()和 write())依賴于底層網絡傳輸所提供的原語。在基于 Java 的網絡編程中,其基本的構造是 class Socket。 Netty 的 Channel 接口所提供的 API,大大地降低了直接使用 Socket 類的復雜性。此外, Channel 也是擁有許多預定義的、專門化實現的廣泛類層次結構的根,下面是一個簡短的部分清單:
每個channel都對應一個物理連接,每個連接都有自己獨立的TCP參數。
> 1. EmbeddedChannel;
> 2. LocalServerChannel;
> 3. NioDatagramChannel;
> 4. NioSctpChannel;
> 5. NioSocketChannel。
1. channel和childHandler
netty服務是父級的、初始的channel線程,負責監聽整個服務。后接入的鏈接都會開啟一個channel,成為childChannel。
在基類AbstractBootstrap有handler方法,目的是添加一個handler,監聽Bootstrap的動作,客戶端的Bootstrap中,繼承了這一點。
在服務端的ServerBootstrap中增加了一個方法childHandler,它的目的是添加handler,用來監聽已經連接的客戶端的Channel的動作和狀態。
handler在初始化時就會執行,而childHandler會在客戶端成功connect后才執行,這是兩者的區別。

如圖所示, 每個 Channel 都將會被分配一個 ChannelPipeline 和 ChannelConfig。ChannelConfig 包含了該 Channel 的所有配置設置, 并且支持熱更新。由于特定的傳輸可能具有獨特的設置, 所以它可能會實現一個 ChannelConfig 的子類型。
Netty 的 Channel 實現是線程安全的,因此你可以存儲一個到 Channel 的引用,并且每當你需要向遠程節點寫數據時, 都可以使用它, 即使當時許多線程都在使用它。
## ChannelHandler
實際的數據業務處理邏輯
1. 針對不同類型的事件來調用 ChannelHandler;
2. 應用程序通過實現或者擴展 ChannelHandler 來掛鉤到事件的生命周期,并且提供自定義的應用程序邏輯;
3. 在架構上, ChannelHandler 有助于保持業務邏輯與網絡處理代碼的分離。這簡化了開發過程,因為代碼必須不斷地演化以響應不斷變化的需求。
4. ChannelInitializer。這是關鍵。當一個新的連接被接受時,一個新的子 Channel 將會被創建,而 ChannelInitializer 將會把一個你的EchoServerHandler 的實例添加到該 Channel 的 ChannelPipeline 中。正如我們之前所
解釋的,這個 ChannelHandler 將會收到有關入站消息的通知
### 方法
#### channelActive()
當有連接建立時調用
#### channelRead(ChannelHandlerContext ctx, Object msg)
1. 每當接收數據時,都會調用這個方法。
2. 需要注意的是,由服務器發送的消息可能會被分塊接收。 也就是說,如果服務器發送了 5 字節, 那么不能保證這 5 字節會被一次性接收。 即使是對于這么少量的數據, channelRead0()方法也可能會被調用兩次,第一次使用一個持有 3 字節的 ByteBuf( Netty 的字節容器),第二次使用一個持有 2 字節的 ByteBuf。作為一個面向流的協議, TCP 保證了字節數組將會按照服務器發送它們的順序被接收。
## ChannelFuture
Netty 中所有的 I/O 操作都是異步的。因為一個操作可能不會立即返回,所以我們需要一種用于在之后的某個時間點確定其結果的方法。為此, Netty 提供了ChannelFuture 接口,其 addListener()方法注冊了一個 ChannelFutureListener,以便在某個操作完成時(無論是否成功)得到通知。
## ChannelPipeline
### 與ChannelHandler的關系
1. 當ChannelHandler 被添加到ChannelPipeline 時,它將會被分配一個ChannelHandlerContext,其代表ChannelHandler 和 ChannelPipeline 之間的綁定。雖然這個對象可以被用于獲取底層的 Channel,但是它主要還是被用于寫出站數據。
2. **ChannelPipeline 提供了 ChannelHandler 鏈的容器**,并定義了用于在該鏈上傳播入站和出站事件流的 API。當 Channel 被創建時, 它會被自動地分配到它專屬的 ChannelPipeline。Handler安裝過程如下:
> 1. 一個ChannelInitializer的實現被注冊到了ServerBootstrap中
> 2. 當 ChannelInitializer.initChannel()方法被調用時, ChannelInitializer將在 ChannelPipeline 中安裝一組自定義的 ChannelHandler
> 3. ChannelInitializer 將它自己從 ChannelPipeline 中移除
### 入、出站

:-: 圖三 數據、事件入站出站示意圖
從一個客戶端應用程序的角度來看,如果事件的運動方向是從客戶端到服務器端, 那么我們稱這些事件為出站的,反之則稱為入站的。
~~~
ChannelInboundHandler :入站Handler
ChannelOutboundHandler :出站Handler
~~~
#### 入站
如果一個消息或者任何其他的入站事件被讀取, 那么它會從 ChannelPipeline 的頭部開始流動,并被傳遞給第一個 ChannelInboundHandler。這個 ChannelHandler 不一定會實際地修改數據, 具體取決于它的具體功能,在這之后,數據將會被傳遞給鏈中的下一個ChannelInboundHandler。最終,數據將會到達 ChannelPipeline 的尾端, 屆時,所有處理就都結束了-**數據處理是一個Handler接著一個Handler執行的。**
#### 出站
數據的出站運動(即正在被寫的數據)在概念上也是一樣的。在這種情況下,數據將從ChannelOutboundHandler 鏈的尾端開始流動,直到它到達鏈的頭部為止。在這之后,出站數據將會到達網絡傳輸層,這里顯示為 Socket。通常情況下,這將觸發一個寫操作。
## ChannelHandlerContext
1. 通過使用作為參數傳遞到每個方法的 ChannelHandlerContext,事件可以被傳遞給當前ChannelHandler 鏈中的下一個 ChannelHandler。
2. 因為你有時會忽略那些不感興趣的事件,所以 Netty提供了抽象基類 ChannelInboundHandlerAdapter 和 ChannelOutboundHandlerAdapter。通過調用 ChannelHandlerContext 上的對應方法,每個都提供了簡單地將事件傳遞給下一個 ChannelHandler的方法的實現。隨后, 你可以通過重寫你所感興趣的那些方法來擴展這些類。
如果將兩個類別的 ChannelHandler都混合添加到同一個 ChannelPipeline 中會發生什么。 雖然 ChannelInboundHandle 和ChannelOutboundHandle 都擴展自 ChannelHandler,但是 Netty 能區分 ChannelInboundHandler 實現和 ChannelOutboundHandler 實現,并確保數據只會在具有相同定向類型的兩個 ChannelHandler 之間傳遞.
### netty發送數據方式
在 Netty 中, 有兩種發送消息的方式:
1. 直接寫到 Channel 中,消息從ChannelPipeline 的尾端開始流動
2. 寫到和 ChannelHandler相關聯的ChannelHandlerContext對象中,消息從 ChannelPipeline 中的下一個 ChannelHandler 開始流動。
### 區別

1. ServerBootstrap 將綁定到一個端口,因為服務器必須要監聽連接, 而 Bootstrap 則是由想要連接到遠程節點的客戶端應用程序所使用的。
2. 引導一個客戶端只需要一個 EventLoopGroup,但是一個ServerBootstrap 則需要兩個(也可以是同一個實例)。
**為什么ServerBootstrap需要兩個EventLoopGroup?**
因為服務器需要兩組不同的 Channel。第一組將只包含一個 ServerChannel,代表服務器自身的已綁定到某個本地端口的在監聽的套接字。 而第二組將包含所有已創建的用來處理傳入客戶端連接( 對于每個服務器已經接受的連接都有一個) 的 Channel。如下圖:

與 ServerChannel 相關聯的 EventLoopGroup 將分配一個負責為傳入連接請求創建Channel的EventLoop。一旦連接被接受,第二個EventLoopGroup就會給它的Channel分配一個EventLoop。
實際上, ServerBootstrap 類也可以只使用一個 EventLoopGroup,此時其將在兩個場景下共用同一個 EventLoopGroup。
## 傳輸


### 1 非阻塞I/O
選擇器背后的基本概念是充當一個注冊表,在那里你將可以請求在 Channel 的狀態發生變化時得到通知并觸發動作。可能的狀態變化有:
> 1. 新的 Channel 已被接受并且就緒;
> 2. Channel 連接已經完成;
> 3. Channel 有已經就緒的可供讀取的數據;
> 4. Channel 可用于寫數據。
對應selector模式

## ByteBuf——Netty 的數據容器
### 讀寫索引
## 異常處理
## channel生命周期

- Docker
- 什么是docker
- Docker安裝、組件啟動
- docker網絡
- docker命令
- docker swarm
- dockerfile
- mesos
- 運維
- Linux
- Linux基礎
- Linux常用命令_1
- Linux常用命令_2
- ip命令
- 什么是Linux
- SELinux
- Linux GCC編譯警告:Clock skew detected. 錯誤解決辦法
- 文件描述符
- find
- 資源統計
- LVM
- Linux相關配置
- 服務自啟動
- 服務器安全
- 字符集
- shell腳本
- shell命令
- 實用腳本
- shell 數組
- 循環與判斷
- 系統級別進程開啟和停止
- 函數
- java調用shell腳本
- 發送郵件
- Linux網絡配置
- Ubuntu
- Ubuntu發送郵件
- 更換apt-get源
- centos
- 防火墻
- 虛擬機下配置網絡
- yum重新安裝
- 安裝mysql5.7
- 配置本地yum源
- 安裝telnet
- 忘記root密碼
- rsync+ crontab
- Zabbix
- Zabbix監控
- Zabbix安裝
- 自動報警
- 自動發現主機
- 監控MySQL
- 安裝PHP常見錯誤
- 基于nginx安裝zabbix
- 監控Tomcat
- 監控redis
- web監控
- 監控進程和端口號
- zabbix自定義監控
- 觸發器函數
- zabbix監控mysql主從同步狀態
- Jenkins
- 安裝Jenkins
- jenkins+svn+maven
- jenkins執行shell腳本
- 參數化構建
- maven區分環境打包
- jenkins使用注意事項
- nginx
- nginx認證功能
- ubuntu下編譯安裝Nginx
- 編譯安裝
- Nginx搭建本地yum源
- 文件共享
- Haproxy
- 初識Haproxy
- haproxy安裝
- haproxy配置
- virtualbox
- virtualbox 復制新的虛擬機
- ubuntu下vitrualbox安裝redhat
- centos配置雙網卡
- 配置存儲
- Windows
- Windows安裝curl
- VMware vSphere
- 磁盤管理
- 增加磁盤
- gitlab
- 安裝
- tomcat
- Squid
- bigdata
- FastDFS
- FastFDS基礎
- FastFDS安裝及簡單實用
- api介紹
- 數據存儲
- FastDFS防盜鏈
- python腳本
- ELK
- logstash
- 安裝使用
- kibana
- 安準配置
- elasticsearch
- elasticsearch基礎_1
- elasticsearch基礎_2
- 安裝
- 操作
- java api
- 中文分詞器
- term vector
- 并發控制
- 對text字段排序
- 倒排和正排索引
- 自定義分詞器
- 自定義dynamic策略
- 進階練習
- 共享鎖和排它鎖
- nested object
- 父子關系模型
- 高亮
- 搜索提示
- Redis
- redis部署
- redis基礎
- redis運維
- redis-cluster的使用
- redis哨兵
- redis腳本備份還原
- rabbitMQ
- rabbitMQ安裝使用
- rpc
- RocketMQ
- 架構概念
- 安裝
- 實例
- 好文引用
- 知乎
- ACK
- postgresql
- 存儲過程
- 編程語言
- 計算機網絡
- 基礎_01
- tcp/ip
- http轉https
- Let's Encrypt免費ssl證書(基于haproxy負載)
- what's the http?
- 網關
- 網絡IO
- http
- 無狀態網絡協議
- Python
- python基礎
- 基礎數據類型
- String
- List
- 遍歷
- Python基礎_01
- python基礎_02
- python基礎03
- python基礎_04
- python基礎_05
- 函數
- 網絡編程
- 系統編程
- 類
- Python正則表達式
- pymysql
- java調用python腳本
- python操作fastdfs
- 模塊導入和sys.path
- 編碼
- 安裝pip
- python進階
- python之setup.py構建工具
- 模塊動態導入
- 內置函數
- 內置變量
- path
- python模塊
- 內置模塊_01
- 內置模塊_02
- log模塊
- collections
- Twisted
- Twisted基礎
- 異步編程初探與reactor模式
- yield-inlineCallbacks
- 系統編程
- 爬蟲
- urllib
- xpath
- scrapy
- 爬蟲基礎
- 爬蟲種類
- 入門基礎
- Rules
- 反反爬蟲策略
- 模擬登陸
- problem
- 分布式爬蟲
- 快代理整站爬取
- 與es整合
- 爬取APP數據
- 爬蟲部署
- collection for ban of web
- crawlstyle
- API
- 多次請求
- 向調度器發送請求
- 源碼學習
- LinkExtractor源碼分析
- 構建工具-setup.py
- selenium
- 基礎01
- 與scrapy整合
- Django
- Django開發入門
- Django與MySQL
- java
- 設計模式
- 單例模式
- 工廠模式
- java基礎
- java位移
- java反射
- base64
- java內部類
- java高級
- 多線程
- springmvc-restful
- pfx數字證書
- 生成二維碼
- 項目中使用log4j
- 自定義注解
- java發送post請求
- Date時間操作
- spring
- 基礎
- spring事務控制
- springMVC
- 注解
- 參數綁定
- springmvc+spring+mybatis+dubbo
- MVC模型
- SpringBoot
- java配置入門
- SpringBoot基礎入門
- SpringBoot web
- 整合
- SpringBoot注解
- shiro權限控制
- CommandLineRunner
- mybatis
- 靜態資源
- SSM整合
- Aware
- Spring API使用
- Aware接口
- mybatis
- 入門
- mybatis屬性自動映射、掃描
- 問題
- @Param 注解在Mybatis中的使用 以及傳遞參數的三種方式
- mybatis-SQL
- 逆向生成dao、model層代碼
- 反向工程中Example的使用
- 自增id回顯
- SqlSessionDaoSupport
- invalid bound statement(not found)
- 脈絡
- beetl
- beetl是什么
- 與SpringBoot整合
- shiro
- 什么是shiro
- springboot+shrio+mybatis
- 攔截url
- 枚舉
- 圖片操作
- restful
- java項目中日志處理
- JSON
- 文件工具類
- KeyTool生成證書
- 兼容性問題
- 開發規范
- 工具類開發規范
- 壓縮圖片
- 異常處理
- web
- JavaScript
- 基礎語法
- 創建對象
- BOM
- window對象
- DOM
- 閉包
- form提交-文件上傳
- td中內容過長
- 問題1
- js高級
- js文件操作
- 函數_01
- session
- jQuery
- 函數01
- data()
- siblings
- index()與eq()
- select2
- 動態樣式
- bootstrap
- 表單驗證
- 表格
- MUI
- HTML
- iframe
- label標簽
- 規范編程
- layer
- sss
- 微信小程序
- 基礎知識
- 實踐
- 自定義組件
- 修改自定義組件的樣式
- 基礎概念
- appid
- 跳轉
- 小程序發送ajax
- 微信小程序上下拉刷新
- if
- 工具
- idea
- Git
- maven
- svn
- Netty
- 基礎概念
- Handler
- SimpleChannelInboundHandler 與 ChannelInboundHandler
- 網絡編程
- 網絡I/O
- database
- oracle
- 游標
- PLSQL Developer
- mysql
- MySQL基準測試
- mysql備份
- mysql主從不同步
- mysql安裝
- mysql函數大全
- SQL語句
- 修改配置
- 關鍵字
- 主從搭建
- centos下用rpm包安裝mysql
- 常用sql
- information_scheme數據庫
- 值得學的博客
- mysql學習
- 運維
- mysql權限
- 配置信息
- 好文mark
- jsp
- jsp EL表達式
- C
- test