如何進(jìn)行Java--Netty的入門

這篇文章將為大家詳細(xì)講解有關(guān)如何進(jìn)行Java--Netty的入門,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

創(chuàng)新互聯(lián)專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、景東網(wǎng)絡(luò)推廣、小程序開發(fā)、景東網(wǎng)絡(luò)營(yíng)銷、景東企業(yè)策劃、景東品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)為所有大學(xué)生創(chuàng)業(yè)者提供景東建站搭建服務(wù),24小時(shí)服務(wù)熱線:18982081108,官方網(wǎng)址:www.muchs.cn

Netty簡(jiǎn)介

Netty是一個(gè)高性能,高可擴(kuò)展性的異步事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架,它極大的簡(jiǎn)化了TCP和UDP客戶端和服務(wù)器端網(wǎng)絡(luò)開發(fā)。它是一個(gè)NIO框架,對(duì)Java NIO進(jìn)行了良好的封裝。作為一個(gè)異步NIO框架,Netty的所有IO操作都是異步非阻塞的,通過Future-Listener機(jī)制,用戶可以方便的主動(dòng)獲取或者通過通知機(jī)制獲得IO操作結(jié)果。

Netty的特性

  • 統(tǒng)一的API,適用于不同的協(xié)議

  • 基于靈活、可擴(kuò)展的事件驅(qū)動(dòng)模型

  • 高度可定制的線程模型

  • 更好的吞吐量,低延遲

  • 更省資源,盡量減少不必要的內(nèi)存拷貝

  • 完整的SSL/TLS和STARTTLS的支持

  • 能在Applet與Android的限制環(huán)境運(yùn)行良好

  • 不再因過快、過慢或超負(fù)載連接導(dǎo)致OutOfMemoryError

  • 不再有在高速網(wǎng)絡(luò)環(huán)境下NIO讀寫頻率不一致的問題

Netty核心內(nèi)容

Netty中最核心的內(nèi)容主要有以下四個(gè)方面:

  • Reactor線程模型:一種高性能的多線程程序設(shè)計(jì)思路

  • Netty中自己定義的Channel概念:增強(qiáng)版的通道概念

  • ChannelPipeline職責(zé)鏈設(shè)計(jì)模式:事件處理機(jī)制

  • 內(nèi)存管理:增強(qiáng)的ByteBuf緩沖區(qū)

Netty整體結(jié)構(gòu)圖

如何進(jìn)行Java--Netty的入門

Netty核心組件

EventLoop:EventLoop維護(hù)了一個(gè)線程和任務(wù)隊(duì)列,支持異步提交執(zhí)行任務(wù)。EventLoop自身實(shí)現(xiàn)了Executor接口,當(dāng)調(diào)用executor方法提交任務(wù)時(shí),則判斷是否啟動(dòng),未啟動(dòng)則調(diào)用內(nèi)置的executor創(chuàng)建新線程來觸發(fā)run方法執(zhí)行,其大致流程參考Netty源碼SingleThreadEventExecutor如下:

如何進(jìn)行Java--Netty的入門

EventLoopGroup:EventLoopGroup主要是管理eventLoop的生命周期,可以將其看作是一個(gè)線程池,其內(nèi)部維護(hù)了一組EventLoop,每個(gè)eventLoop對(duì)應(yīng)處理多個(gè)Channel,而一個(gè)Channel只能對(duì)應(yīng)一個(gè)EventLoop

如何進(jìn)行Java--Netty的入門

Bootstrap:BootStrap 是客戶端的引導(dǎo)類,主要用于客戶端連接遠(yuǎn)程主機(jī),有1個(gè)EventLoopGroup。Bootstrap 在調(diào)用 bind()(連接UDP)和 connect()(連接TCP)方法時(shí),會(huì)新創(chuàng)建一個(gè)單獨(dú)的、沒有父 Channel 的 Channel 來實(shí)現(xiàn)所有的網(wǎng)絡(luò)交換。

ServerBootstrap:ServerBootstrap 是服務(wù)端的引導(dǎo)類,主要用戶服務(wù)端綁定本地端口,有2個(gè)EventLoopGroup。ServerBootstarp 在調(diào)用 bind() 方法時(shí)會(huì)創(chuàng)建一個(gè) ServerChannel 來接受來自客戶端的連接,并且該 ServerChannel 管理了多個(gè)子 Channel 用于同客戶端之間的通信。

Channel:Netty中的Channel是一個(gè)抽象的概念,可以理解為對(duì)Java NIO Channel的增強(qiáng)和擴(kuò)展,增加了許多新的屬性和方法,如bing方法等。

ChannelFuture:ChannelFuture能夠注冊(cè)一個(gè)或者多個(gè)ChannelFutureListener 實(shí)例,當(dāng)操作完成時(shí),不管成功還是失敗,均會(huì)被通知。ChannelFuture存儲(chǔ)了之后執(zhí)行的操作的結(jié)果并且無法預(yù)測(cè)操作何時(shí)被執(zhí)行,提交至Channel的操作按照被喚醒的順序被執(zhí)行。

ChannelHandler:ChannelHandler用來處理業(yè)務(wù)邏輯,分別有入站和出站的實(shí)現(xiàn)。

ChannelPipeline:ChannelPipeline 提供了 ChannelHandler鏈的容器,并定義了用于在該鏈上傳播入站和出站事件流的API。

Netty線程模型

Netty的線程模型是基于Reactor模式的線程實(shí)現(xiàn)。關(guān)于Reactor模式可以參考Reactor模式 ,Netty中依據(jù)用戶的配置可以支持單線程的Reactor模型,多線程的Reactor模型以及主從多Reactor的模型。在Netty中其大致流程如下如下:

如何進(jìn)行Java--Netty的入門

Netty入門代碼示例

服務(wù)端代碼示例:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.nio.charset.Charset;
public class EchoServer {
 public static void main(String[] args) {

   // accept線程組,用來接受連接
   EventLoopGroup bossGroup = new NioEventLoopGroup(1);

   // I/O線程組, 用于處理業(yè)務(wù)邏輯
   EventLoopGroup workerGroup = new NioEventLoopGroup(1);

   try {
     // 服務(wù)端啟動(dòng)引導(dǎo)
     ServerBootstrap b = new ServerBootstrap();

     b.group(bossGroup, workerGroup) // 綁定兩個(gè)線程組
         .channel(NioServerSocketChannel.class) // 指定通道類型
         .option(ChannelOption.SO_BACKLOG, 100) // 設(shè)置TCP連接的緩沖區(qū)
         .handler(new LoggingHandler(LogLevel.INFO)) // 設(shè)置日志級(jí)別
         .childHandler(
             new ChannelInitializer<SocketChannel>() {
               @Override
               protected void initChannel(SocketChannel socketChannel) throws Exception {
                 ChannelPipeline pipeline = socketChannel.pipeline(); // 獲取處理器鏈
                 pipeline.addLast(new EchoServerHandler()); // 添加新的件處理器

               }

             });

     // 通過bind啟動(dòng)服務(wù)
     ChannelFuture f = b.bind(8080).sync();

     // 阻塞主線程,知道網(wǎng)絡(luò)服務(wù)被關(guān)閉
     f.channel().closeFuture().sync();

   } catch (Exception e) {
     e.printStackTrace();
   } finally {
     workerGroup.shutdownGracefully();
     bossGroup.shutdownGracefully();
   }
 }

}

class EchoServerHandler extends ChannelInboundHandlerAdapter {

 // 每當(dāng)從客戶端收到新的數(shù)據(jù)時(shí),這個(gè)方法會(huì)在收到消息時(shí)被調(diào)用
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   System.out.println("收到數(shù)據(jù):" + ((ByteBuf) msg).toString(Charset.defaultCharset()));
   ctx.write(Unpooled.wrappedBuffer("Server message".getBytes()));
   ctx.fireChannelRead(msg);
 }
 // 數(shù)據(jù)讀取完后被調(diào)用  @Override
 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
   ctx.flush();
 }
 // 當(dāng)Netty由于IO錯(cuò)誤或者處理器在處理事件時(shí)拋出的異常時(shí)被調(diào)用  @Override
 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
   cause.printStackTrace();
   ctx.close();
 }
}

客戶端代碼示例:

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.nio.charset.Charset;
public class EchoClient {
 public static void main(String[] args) {
   EventLoopGroup group = new NioEventLoopGroup();
   try {
     Bootstrap b = new Bootstrap();
     b.group(group)
         .channel(NioSocketChannel.class)
         .option(ChannelOption.TCP_NODELAY, true)
         .handler(
             new ChannelInitializer<SocketChannel>() {
               @Override
               public void initChannel(SocketChannel ch) throws Exception {
                 ChannelPipeline p = ch.pipeline();
                 p.addLast(new EchoClientHandler());
               }
             });
     ChannelFuture f = b.connect("127.0.0.1", 8080).sync();
     f.channel().closeFuture().sync();
   } catch (Exception e) {
     e.printStackTrace();
   } finally {
     group.shutdownGracefully();
   }
 }

}

class EchoClientHandler extends ChannelInboundHandlerAdapter {
 private final ByteBuf firstMessage;
 public EchoClientHandler() {
   firstMessage = Unpooled.buffer(256);
   for (int i = 0; i < firstMessage.capacity(); i++) {
     firstMessage.writeByte((byte) i);
   }
 }
 @Override
 public void channelActive(ChannelHandlerContext ctx) {
   ctx.writeAndFlush(firstMessage);
 }
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) {
   System.out.println("收到數(shù)據(jù):" + ((ByteBuf) msg).toString(Charset.defaultCharset()));
   ctx.write(Unpooled.wrappedBuffer("Client message".getBytes()));
 }
 @Override
 public void channelReadComplete(ChannelHandlerContext ctx) {
   ctx.flush();
 }
 @Override
 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
   cause.printStackTrace();
   ctx.close();
 }
}

關(guān)于如何進(jìn)行Java--Netty的入門就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

網(wǎng)頁題目:如何進(jìn)行Java--Netty的入門
網(wǎng)頁地址:http://www.muchs.cn/article38/geeesp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、做網(wǎng)站外貿(mào)網(wǎng)站建設(shè)、搜索引擎優(yōu)化、建站公司、電子商務(wù)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站