自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

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

它極大地簡化并優(yōu)化了 TCP 和 UDP 套接字服務(wù)器等網(wǎng)絡(luò)編程,并且性能以及安全性等很多方面甚至都要更好。

支持多種協(xié)議 如 FTP,SMTP,HTTP 以及各種二進(jìn)制和基于文本的傳統(tǒng)協(xié)議。

用官方的總結(jié)就是:Netty 成功地找到了一種在不妥協(xié)可維護(hù)性和性能的情況下實現(xiàn)易于開發(fā),性能,穩(wěn)定性和靈活性的方法。

為什么要用Netty

Netty作為一款優(yōu)秀的網(wǎng)絡(luò)框架,自然有令人折服的特點:

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

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

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

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

社區(qū):Netty快速發(fā)展的一個重要的原因就是它的社區(qū)非?;钴S,這也使得采用它的開發(fā)者越來越多。

Netty的簡單使用

左邊是服務(wù)端代碼,右邊是客戶端代碼。

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

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

ServerBootstrap 類用于創(chuàng)建服務(wù)端實例,Bootstrap 用于創(chuàng)建客戶端實例。

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

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

當(dāng)然,也有對其他協(xié)議的支持,如支持 UDP 協(xié)議的 NioDatagramChannel,本文只關(guān)心 TCP 相關(guān)的。

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

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

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

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

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

Netty核心組件

Bytebuf(字節(jié)容器)

網(wǎng)絡(luò)通信最終都是通過字節(jié)流進(jìn)行傳輸?shù)?。ByteBuf 就是 Netty 提供的一個字節(jié)容器,其內(nèi)部是一個字節(jié)數(shù)組。當(dāng)我們通過 Netty 傳輸數(shù)據(jù)的時候,就是通過 ByteBuf 進(jìn)行的。

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

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

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

Bootstrap 和 ServerBootstrap(啟動引導(dǎo)類)

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

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

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

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

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

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

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

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

Channel(網(wǎng)絡(luò)操作抽象類)

Channel 接口是 Netty 對網(wǎng)絡(luò)操作抽象類。通過 Channel 我們可以進(jìn)行 I/O 操作。

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

//  通過 Bootstrap 的 connect 方法連接到服務(wù)端
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接口實現(xiàn)類是 :

NioServerSocketChannel(服務(wù)端)

NioSocketChannel(客戶端)

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

EventLoop(事件循環(huán))

EventLoop 介紹

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

《Netty 實戰(zhàn)》這本書是這樣介紹它的:

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

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

說白了,EventLoop 的主要作用實際就是責(zé)監(jiān)聽網(wǎng)絡(luò)事件并調(diào)用事件處理器進(jìn)行相關(guān) I/O 操作(讀寫)的處理。

Channel 和 EventLoop 的關(guān)系

那 Channel 和 EventLoop 直接有啥聯(lián)系呢?

Channel 為 Netty 網(wǎng)絡(luò)操作(讀寫等操作)抽象類,EventLoop 負(fù)責(zé)處理注冊到其上的Channel 的 I/O 操作,兩者配合進(jìn)行 I/O 操作。

EventloopGroup 和 EventLoop 的關(guān)系

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

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

下圖是 Netty NIO 模型對應(yīng)的 EventLoop 模型。通過這個圖應(yīng)該可以將EventloopGroup、EventLoop、 Channel三者聯(lián)系起來。

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

下面這段代碼使用過 Netty 的小伙伴應(yīng)該不會陌生,我們指定了序列化編解碼器以及自定義的 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 是消息的具體處理器,主要負(fù)責(zé)處理客戶端/服務(wù)端接收和發(fā)送的數(shù)據(jù)。

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

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

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

ChannelFuture(操作執(zhí)行結(jié)果)

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需要底層操作系統(tǒng)的支持,異步是說數(shù)據(jù)準(zhǔn)備好之后由系統(tǒng)通知應(yīng)用程序你可以來操作數(shù)據(jù)了,而netty所謂的異步是另起一個用戶線程等待數(shù)據(jù)就緒并通過回調(diào)處理,并不是真正意義上的異步io

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

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

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

Channel channel = f.channel();

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

//bind()是異步的,但是,你可以通過 `sync()`方法將其變?yōu)橥健?br>ChannelFuture f = b.bind(port).sync();

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

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

責(zé)任編輯:武曉燕 來源: 左耳君
相關(guān)推薦

2024-08-01 17:34:56

Promiseaxios請求

2024-02-07 12:35:00

React并發(fā)模式concurrent

2025-03-10 11:48:10

人工智能AI軟件

2021-05-11 07:30:58

JNIJavaAPI

2021-01-28 17:41:32

Github網(wǎng)站Pull Reques

2022-04-10 19:26:07

TypeScript類型語法

2016-03-03 17:42:10

DockerDCOS

2024-07-12 15:08:23

Python@wraps函數(shù)

2024-08-26 14:23:56

2021-12-26 00:01:51

Log4Shell漏洞服務(wù)器

2022-09-06 21:38:45

數(shù)字人數(shù)字孿生

2021-12-16 15:11:59

Facebook天秤幣加密貨幣

2022-06-01 07:58:31

渲染3D

2013-05-29 10:17:56

Hadoop分布式文件系統(tǒng)

2012-07-25 09:09:46

GNOME OS桌面

2022-12-30 08:35:00

2024-02-26 00:00:00

人工智能序列數(shù)據(jù)機(jī)器人

2020-03-07 09:47:48

AVL樹算法場景

2020-10-29 07:03:56

Docker容器存儲

2024-02-01 20:15:37

點贊
收藏

51CTO技術(shù)棧公眾號