日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

漫谈NIO(3)之Netty实现

發(fā)布時間:2023/10/19 编程问答 101 如意码农
生活随笔 收集整理的這篇文章主要介紹了 漫谈NIO(3)之Netty实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.前言

上一章結(jié)合Java的NIO例子,講解了多路IO復(fù)用的一個基本使用方法,通過實際編碼加深對其理解。本章開始進(jìn)入Netty的環(huán)節(jié),前面兩章都是為了Netty進(jìn)行鋪墊說明。此節(jié)將對比Java的NIO例子,說明Netty的一個基本設(shè)計,如果前面理解透徹,對Netty的學(xué)習(xí)將非常有幫助。

國際慣例,將Netty官網(wǎng)的基本描述放上:Netty是一個為了快速開發(fā)可維護(hù)的高性能協(xié)議服務(wù)器和客戶端的異步事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用程序框架。快速簡單并不意味著應(yīng)用會受到可維護(hù)和性能問題。其設(shè)計非常謹(jǐn)慎,使用了多種協(xié)議,如FTP、SMTP、HTTP和各種二進(jìn)制和基于文本的遺留協(xié)議。Netty成功的找到了一種方法,可以在不妥協(xié)的情況下實現(xiàn)開發(fā)、性能、穩(wěn)定、靈活。

以上的描述主要關(guān)注的就兩點(diǎn):1.異步事件驅(qū)動;2.多種協(xié)議解析。另外,Netty有較高的吞吐量,低延遲,更少的資源浪費(fèi),最小不必要的內(nèi)存拷貝。

2.例子

2.1 服務(wù)端

Java的NIO中我提到服務(wù)端基礎(chǔ)的4個內(nèi)容:1.線程池;2.端口;3.Selector;4.Channel。Netty實際上也就是這些內(nèi)容,但是Netty作為一個封裝好了的框架,其不會讓我們自己獲取Selector,畢竟不是所有的IO都是這種方式,連接過程進(jìn)行的封裝(連接、讀取、寫入、斷開連接),另一個就是在之前沒有講到的協(xié)議解析。我們都知道TCP實際上是有粘包的問題,一般需要一個協(xié)議避免這個問題,前面也說到了Netty支持很多協(xié)議,demo會體現(xiàn)這一點(diǎn)。

    public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(); try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("===>receive msg:" + msg);
ctx.channel().writeAndFlush("server get msg:" + msg +"\r\n");
}
});
}
});
ChannelFuture future = bootstrap.bind(7777).sync();
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}

EventLoopGroup就是Netty根據(jù)JDK提供的線程池框架進(jìn)行二次封裝的一個線程池類。ServerBootstrap是啟動類,首先要對其進(jìn)行一系列設(shè)置:1.設(shè)置線程池;2.設(shè)置IO方式(由channel確定);3.設(shè)置handler(handler就是Netty的一個非常重要的封裝了,實際上我們對于IO關(guān)心的就只有連接的生命周期而已,handler就是對于連接的各個生命周期提供了一個處理相應(yīng)業(yè)務(wù)的入口);4.綁定端口。這個和Java的例子前面部分是不是很像,只是對于事件的處理不需要開發(fā)者關(guān)注了,取而代之的是開發(fā)者只需要關(guān)注handler對連接各個階段的處理即可,根據(jù)channel類型的不同,Netty對于IO事件的處理全部轉(zhuǎn)換成了Handler。

這里我們主要關(guān)注的就是handler了,這對于之前是一個新概念。上面例子就設(shè)計了一個最簡單的handler了,handler采取的是職責(zé)鏈設(shè)計模式,并且其是有先后順序的,這個不能亂。想一下,讀取數(shù)據(jù),讀出來的都是二進(jìn)制,第一步當(dāng)然就是對二進(jìn)制進(jìn)行解析,解析出一個完整的協(xié)議,多的部分不要,少了繼續(xù)等待數(shù)據(jù)到來。DelimiterBasedFrameDecoder就是進(jìn)行了這個操作,其以換行符作為約定的協(xié)議。獲取協(xié)議之后第二步自然是解析協(xié)議了,StringDecoder就是這個用處,即我們希望客戶端發(fā)送的是帶換行符的字符串。那么StringEncoder是干啥用的?這個不是對協(xié)議進(jìn)行編碼嗎?實際上hander管理了讀取的處理,也管理寫的操作,我們也需要一個協(xié)議返回給客戶端。所以handler分為兩類,in和out,in會處理read事件,out會處理write事件。最后一個handler就是自定義的一個in類型的handler了,解析完協(xié)議后我們要做什么操作,就在這里完成了,這個就是我們的業(yè)務(wù)層。

2.2 客戶端

客戶端之前沒有使用線程池,但是Netty依舊使用了線程池,因為又不是只有socket需要線程處理,耗時不需要同步執(zhí)行的業(yè)務(wù)操作也可以使用多線程技術(shù)。其它的地方區(qū)別就不是很大了,具體看代碼。

    public static void main(String[] args) {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group);
b.channel(NioSocketChannel.class);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg);
}
});
}
}); Channel ch = b.connect("127.0.0.1", 7777).sync().channel();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while(true) {
line = in.readLine();
if("close".equals(line)) {
break;
}
ch.writeAndFlush(line + '\n');
}
ch.close().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}

上面代碼有個特殊的地方在于其只需要一個線程池,服務(wù)端設(shè)置的bossGroup看上章的內(nèi)容應(yīng)該也容易理解,服務(wù)端的主線程實際上是被select阻塞了的,所以服務(wù)端Netty對于主線程也交由線程池處理了,客戶端不存在這個問題。

3.Netty核心概念

上面是一個非常基礎(chǔ)的demo,但是麻雀雖小五臟俱全(也許不算全),其給出了Netty中幾個重要的概念。

Bootstrap或者是ServerBootstrap:Netty的啟動類,基本的參數(shù),選擇都要在這里設(shè)置完成。

EventLoopGroup或者是EventLoop:Netty封裝的線程池,需要針對channel選擇合適的線程池

  Channel:Netty對于不同的IO處理是由Channel決定的,Channel中有其它核心的概念,這里不進(jìn)行介紹

  Handler:處理IO各個生命周期節(jié)點(diǎn)的對應(yīng)類,handler也產(chǎn)生了一系列概念,這個之后介紹。

  Future或者是Promise:這個是異步的核心,主要獲取異步操作的結(jié)果,很重要。

這5個是由demo得出來的核心內(nèi)容,實際上Netty很復(fù)雜,由這些核心會引出其它的核心內(nèi)容。這里不進(jìn)行介紹,相關(guān)章節(jié)會進(jìn)行說明。

4.后記

本節(jié)主要是貫穿前面的章節(jié),以Netty和Java的例子,對Netty進(jìn)行一個入門的了解,有了Java例子的基礎(chǔ),就不會對Netty的簡單配置最終為什么能達(dá)到所要的效果一無所知。仔細(xì)思考就能大致明白Netty的Nio是如何處理的了。后續(xù)章節(jié)將以Netty核心概念為主題,介紹Netty整體的一個結(jié)構(gòu)。

總結(jié)

以上是生活随笔為你收集整理的漫谈NIO(3)之Netty实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。