成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Netty到底是個啥?你明白了嗎?

開發 架構
Netty 是一個利用Java的高級網絡能力,隱藏其(Java API)背后的復雜性而提供一個易于使用的 NIO 客戶端/服務端框架。

Netty 是一個利用Java的高級網絡能力,隱藏其(Java API)背后的復雜性而提供一個易于使用的 NIO 客戶端/服務端框架。

它極大地簡化并優化了 TCP 和 UDP 套接字服務器等網絡編程,并且性能以及安全性等很多方面甚至都要更好。

支持多種協議 如 FTP,SMTP,HTTP 以及各種二進制和基于文本的傳統協議。

用官方的總結就是:Netty 成功地找到了一種在不妥協可維護性和性能的情況下實現易于開發,性能,穩定性和靈活性的方法。

為什么要用Netty

Netty作為一款優秀的網絡框架,自然有令人折服的特點:

設計:針對多種傳輸類型的同一接口。簡單但更強大的線程模型。真正的無連接的數據報套接字支持。鏈接邏輯復用。

性能:Netty的高性能是它被廣泛使用的一個重要的原因,我們可能都認為Java不太適合 編寫游戲服務端程序,但Netty的到來無疑是降低了懷疑的聲音。

較原生Java API有更好的吞吐量,較低的延時。資源消耗更少(共享池和重用)。減少內存拷貝。

健壯性:原生NIO的客戶端/服務端程序編寫較為麻煩,如果某個地方處理的不好,可能會 導致一些意料之外的異常,如內存溢出,死循環等等,而Netty則為我們簡化了原生API 的使用,這使得我們編寫出來的程序不那么容易出錯。

社區:Netty快速發展的一個重要的原因就是它的社區非常活躍,這也使得采用它的開發者越來越多。

Netty的簡單使用

左邊是服務端代碼,右邊是客戶端代碼。

上面的代碼基本就是模板代碼,每次使用都是這一個套路,唯一需要我們開發的部分是 handler(…) 和 childHandler(…) 方法中指定的各個 handler,如 EchoServerHandler 和 EchoClientHandler,當然 Netty 源碼也給我們提供了很多的 handler,比如上面的 LoggingHandler,它就是 Netty 源碼中為我們提供的,需要的時候直接拿過來用就好了。

我們先來看一下上述代碼中涉及到的一些內容:

ServerBootstrap 類用于創建服務端實例,Bootstrap 用于創建客戶端實例。

兩個 EventLoopGroup:bossGroup 和 workerGroup,它們涉及的是 Netty 的線程模型,可以看到服務端有兩個 group,而客戶端只有一個,它們就是 Netty 中的線程池。

Netty 中的 Channel,沒有直接使用 Java 原生的 ServerSocketChannel 和 SocketChannel,而是包裝了 NioServerSocketChannel 和 NioSocketChannel 與之對應。

當然,也有對其他協議的支持,如支持 UDP 協議的 NioDatagramChannel,本文只關心 TCP 相關的。

左邊 handler(…) 方法指定了一個 handler(LoggingHandler),這個 handler 是給服務端收到新的請求的時候處理用的。右邊 handler(...) 方法指定了客戶端處理請求過程中需要使用的 handlers。

如果你想在 EchoServer 中也指定多個 handler,也可以像右邊的 EchoClient 一樣使用 ChannelInitializer

左邊 childHandler(…) 指定了 childHandler,這邊的 handlers 是給新創建的連接用的,我們知道服務端 ServerSocketChannel 在 accept 一個連接以后,需要創建 SocketChannel 的實例,childHandler(…) 中設置的 handler 就是用于處理新創建的 SocketChannel 的,而不是用來處理 ServerSocketChannel 實例的。

pipeline:handler 可以指定多個(需要上面的 ChannelInitializer 類輔助),它們會組成了一個 pipeline,它們其實就類似攔截器的概念,現在只要記住一點,每個 NioSocketChannel 或 NioServerSocketChannel 實例內部都會有一個 pipeline 實例。pipeline 中還涉及到 handler 的執行順序。

ChannelFuture:這個涉及到 Netty 中的異步編程,和 JDK 中的 Future 接口類似。

Netty核心組件

Bytebuf(字節容器)

網絡通信最終都是通過字節流進行傳輸的。ByteBuf 就是 Netty 提供的一個字節容器,其內部是一個字節數組。當我們通過 Netty 傳輸數據的時候,就是通過 ByteBuf 進行的。

我們可以將 ByteBuf 看作是 Netty 對 Java NIO 提供了 ByteBuffer 字節容器的封裝和抽象。

有很多小伙伴可能就要問了 :為什么不直接使用 Java NIO 提供的 ByteBuffer 呢?

因為 ByteBuffer 這個類使用起來過于復雜和繁瑣。

Bootstrap 和 ServerBootstrap(啟動引導類)

Bootstrap 是客戶端的啟動引導類/輔助類,具體使用方法如下:

EventLoopGroup group = new NioEventLoopGroup();
try {
//創建客戶端啟動引導/輔助類:Bootstrap
Bootstrap b = new Bootstrap();
//指定線程模型
b.group(group).
......
// 嘗試建立連接
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} finally {
// 優雅關閉相關線程組資源
group.shutdownGracefully();
}

ServerBootstrap 客戶端的啟動引導類/輔助類,具體使用方法如下:

 // 1.bossGroup 用于接收連接,workerGroup 用于具體的處理
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//2.創建服務端啟動引導/輔助類:ServerBootstrap
ServerBootstrap b = new ServerBootstrap();
//3.給引導類配置兩大線程組,確定了線程模型
b.group(bossGroup, workerGroup).
......
// 6.綁定端口
ChannelFuture f = b.bind(port).sync();
// 等待連接關閉
f.channel().closeFuture().sync();
} finally {
//7.優雅關閉相關線程組資源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}

從上面的示例中,我們可以看出:

Bootstrap 通常使用 connet() 方法連接到遠程的主機和端口,作為一個 Netty TCP 協議通信中的客戶端。另外,Bootstrap 也可以通過 bind() 方法綁定本地的一個端口,作為 UDP 協議通信中的一端。

ServerBootstrap通常使用 bind() 方法綁定本地的端口上,然后等待客戶端的連接。

Bootstrap 只需要配置一個線程組— EventLoopGroup ,而 ServerBootstrap需要配置兩個線程組— EventLoopGroup ,一個用于接收連接,一個用于具體的 IO 處理。

Channel(網絡操作抽象類)

Channel 接口是 Netty 對網絡操作抽象類。通過 Channel 我們可以進行 I/O 操作。

一旦客戶端成功連接服務端,就會新建一個 Channel 同該用戶端進行綁定,示例代碼如下:

//  通過 Bootstrap 的 connect 方法連接到服務端
public Channel doConnect(InetSocketAddress inetSocketAddress) {
CompletableFuture<Channel> completableFuture = new CompletableFuture<>();
bootstrap.connect(inetSocketAddress).addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {
completableFuture.complete(future.channel());
} else {
throw new IllegalStateException();
}
});
return completableFuture.get();
}

比較常用的Channel接口實現類是 :

NioServerSocketChannel(服務端)

NioSocketChannel(客戶端)

這兩個 Channel 可以和 BIO 編程模型中的ServerSocket以及Socket兩個概念對應上。

EventLoop(事件循環)

EventLoop 介紹

這么說吧!EventLoop(事件循環)接口可以說是 Netty 中最核心的概念了!

《Netty 實戰》這本書是這樣介紹它的:

EventLoop 定義了 Netty 的核心抽象,用于處理連接的生命周期中所發生的事件。

是不是很難理解?說實話,我學習 Netty 的時候看到這句話是沒太能理解的。

說白了,EventLoop 的主要作用實際就是責監聽網絡事件并調用事件處理器進行相關 I/O 操作(讀寫)的處理。

Channel 和 EventLoop 的關系

那 Channel 和 EventLoop 直接有啥聯系呢?

Channel 為 Netty 網絡操作(讀寫等操作)抽象類,EventLoop 負責處理注冊到其上的Channel 的 I/O 操作,兩者配合進行 I/O 操作。

EventloopGroup 和 EventLoop 的關系

EventLoopGroup 包含多個 EventLoop(每一個 EventLoop 通常內部包含一個線程),它管理著所有的 EventLoop 的生命周期。

并且,EventLoop 處理的 I/O 事件都將在它專有的 Thread 上被處理,即 Thread 和 EventLoop 屬于 1 : 1 的關系,從而保證線程安全。

下圖是 Netty NIO 模型對應的 EventLoop 模型。通過這個圖應該可以將EventloopGroup、EventLoop、 Channel三者聯系起來。

ChannelHandler(消息處理器) 和 ChannelPipeline(ChannelHandler 對象鏈表)

下面這段代碼使用過 Netty 的小伙伴應該不會陌生,我們指定了序列化編解碼器以及自定義的 ChannelHandler 處理消息。

b.group(eventLoopGroup)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new NettyKryoDecoder(kryoSerializer, RpcResponse.class));
ch.pipeline().addLast(new NettyKryoEncoder(kryoSerializer, RpcRequest.class));
ch.pipeline().addLast(new KryoClientHandler());
}
});

ChannelHandler 是消息的具體處理器,主要負責處理客戶端/服務端接收和發送的數據。

當 Channel 被創建時,它會被自動地分配到它專屬的 ChannelPipeline。一個Channel包含一個 ChannelPipeline。ChannelPipeline 為 ChannelHandler 的鏈,一個 pipeline 上可以有多個 ChannelHandler。

我們可以在 ChannelPipeline 上通過 addLast() 方法添加一個或者多個ChannelHandler (一個數據或者事件可能會被多個 Handler 處理) 。當一個 ChannelHandler 處理完之后就將數據交給下一個 ChannelHandler 。

當 ChannelHandler 被添加到的 ChannelPipeline 它得到一個 ChannelHandlerContext,它代表一個 ChannelHandler 和 ChannelPipeline 之間的“綁定”。ChannelPipeline 通過 ChannelHandlerContext來間接管理 ChannelHandler 。

ChannelFuture(操作執行結果)

public interface ChannelFuture extends Future<Void> {
Channel channel();

ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> var1);
......

ChannelFuture sync() throws InterruptedException;
}

Netty 是異步非阻塞的,所有的 I/O 操作都為異步的。

Netty實際上是不支持異步io的,真正的異步io需要底層操作系統的支持,異步是說數據準備好之后由系統通知應用程序你可以來操作數據了,而netty所謂的異步是另起一個用戶線程等待數據就緒并通過回調處理,并不是真正意義上的異步io

因此,我們不能立刻得到操作是否執行成功,但是,你可以通過 ChannelFuture 接口的 addListener() 方法注冊一個 ChannelFutureListener,當操作執行成功或者失敗時,監聽就會自動觸發返回結果。

ChannelFuture f = b.connect(host, port).addListener(future -> {
if (future.isSuccess()) {
System.out.println("連接成功!");
} else {
System.err.println("連接失敗!");
}
}).sync();

并且,你還可以通過ChannelFuture 的 channel() 方法獲取連接相關聯的Channel 。

Channel channel = f.channel();

另外,我們還可以通過 ChannelFuture 接口的 sync()方法讓異步的操作編程同步的。

//bind()是異步的,但是,你可以通過 `sync()`方法將其變為同步。
ChannelFuture f = b.bind(port).sync();

本文參考:https://www.javadoop.com/post/netty-part-1

本文參考:https://github.com/Snailclimb/netty-practical-tutorial

責任編輯:武曉燕 來源: 左耳君
相關推薦

2024-08-01 17:34:56

Promiseaxios請求

2024-02-07 12:35:00

React并發模式concurrent

2025-03-10 11:48:10

人工智能AI軟件

2021-05-11 07:30:58

JNIJavaAPI

2021-01-28 17:41:32

Github網站Pull Reques

2016-03-03 17:42:10

DockerDCOS

2022-04-10 19:26:07

TypeScript類型語法

2024-07-12 15:08:23

Python@wraps函數

2021-12-26 00:01:51

Log4Shell漏洞服務器

2024-08-26 14:23:56

2021-12-16 15:11:59

Facebook天秤幣加密貨幣

2022-09-06 21:38:45

數字人數字孿生

2022-06-01 07:58:31

渲染3D

2022-12-30 08:35:00

2013-05-29 10:17:56

Hadoop分布式文件系統

2012-07-25 09:09:46

GNOME OS桌面

2021-11-07 14:34:26

跨域網絡后端

2024-02-26 00:00:00

人工智能序列數據機器人

2020-03-07 09:47:48

AVL樹算法場景

2020-10-29 07:03:56

Docker容器存儲
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美成人精品一区二区三区 | 91精品国产综合久久久久久丝袜 | 一区二区三区免费 | 精品国产视频在线观看 | 国产精品中文在线 | 欧美老少妇一级特黄一片 | 无码日韩精品一区二区免费 | 99热热99| 亚洲国产精品suv | 亚洲精品一区中文字幕乱码 | 一本久久a久久精品亚洲 | 久久机热 | 神马久久久久久久久久 | 久久国产一区二区 | 一区二区三区在线 | 欧 | 欧美成人猛片aaaaaaa | 国产精品成人一区二区 | 精品久久久久久亚洲综合网站 | 国产精品成人一区二区三区 | 午夜影院在线观看免费 | 日日日操| 日韩在线| 日韩在线中文字幕 | 亚洲精品欧美 | 欧美精品一区免费 | 91影院| 精品成人免费一区二区在线播放 | 日韩一区二| 野狼在线社区2017入口 | 国产精品久久久久久妇女6080 | 中文天堂在线一区 | 在线观看黄视频 | 成年人在线观看 | 一级黄色片免费 | 亚洲视频国产视频 | 欧美影院久久 | 九九热在线免费视频 | 国产精品99久久久久久宅男 | 亚洲欧洲精品成人久久奇米网 | 毛片.com| 成在线人视频免费视频 |