1. 程式人生 > >初識Netty,Java-NIO

初識Netty,Java-NIO

在這裡插入圖片描述

Netty和Tomcat有什麼區別?

Netty和Tomcat最大的區別就在於通訊協議,Tomcat是基於Http協議的,他的實質是一個基於http協議的web容器,但是Netty不一樣,他能通過程式設計自定義各種協議,因為netty能夠通過codec自己來編碼/解碼位元組流,完成類似redis訪問的功能,這就是netty和tomcat最大的不同。
特點:
併發高;
傳輸快;
封裝好;

重要結構: selector

NIO中,當一個Socket建立好之後,Thread並不會阻塞去接受這個Socket,而是將這個請求交給Selector,Selector會不斷的去遍歷所有的Socket,一旦有一個Socket建立完成,他會通知Thread,然後Thread處理完資料再返回給客戶端——這個過程是阻塞的,這樣就能讓一個Thread處理更多的請求了。

NIO為同步非阻塞IO,阻塞業務處理但不阻塞資料接收(不阻塞請求的接收,接收到的請求交給一個執行緒,讓執行緒去處理這些請求),適用於高併發且處理簡單的場景。

Netty為什麼傳輸快

Netty的傳輸快其實也是依賴了NIO的一個特性——零拷貝。
我們知道,Java的記憶體有堆記憶體、棧記憶體和字串常量池等等,其中堆記憶體是佔用記憶體空間最大的一塊,也是Java物件存放的地方,一般我們的資料如果需要從IO讀取到堆記憶體,中間需要經過Socket緩衝區,也就是說一個數據會被拷貝兩次才能到達他的的終點,如果資料量大,就會造成不必要的資源浪費。
Netty針對這種情況,使用了NIO中的另一大特性——零拷貝,當他需要接收資料的時候,他會在堆記憶體之外開闢一塊記憶體,資料就直接從IO讀到了那塊記憶體中去,在netty裡面通過ByteBuf

可以直接對這些資料進行直接操作,從而加快了傳輸速度。

   public class NettyOioServer {
    
        public void server(int port) throws Exception {
            final ByteBuf buf = Unpooled.unreleasableBuffer(
                    Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8")));
            EventLoopGroup group = new OioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();        //1
    
                b.group(group)                                    //2
                 .channel(OioServerSocketChannel.class)
                 .localAddress(new InetSocketAddress(port))
                 .childHandler(new ChannelInitializer<SocketChannel>() {//3
                     @Override
                     public void initChannel(SocketChannel ch) 
                         throws Exception {
                         ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {            //4
                             @Override
                             public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                 ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOSE);//5
                             }
                         });
                     }
                 });
                ChannelFuture f = b.bind().sync();  //6
                f.channel().closeFuture().sync();
            } finally {
                group.shutdownGracefully().sync();        //7
            }
        }
    }

Netty的一些重要概念:
Channel
資料傳輸流,與channel相關的概念有以下四個,上一張圖讓你瞭解netty裡面的Channel。
在這裡插入圖片描述

Channel一覽
Channel,表示一個連線,可以理解為每一個請求,就是一個ChannelChannelHandler,核心處理業務就在這裡,用於處理業務請求。 ChannelHandlerContext,用於傳輸業務資料。 ChannelPipeline,用於儲存處理過程需要用到的ChannelHandler和ChannelHandlerContext。

ByteBuf
ByteBuf是一個儲存位元組的容器,最大特點就是使用方便,它既有自己的讀索引和寫索引,方便你對整段位元組快取進行讀寫,也支援get/set,方便你對其中每一個位元組進行讀寫,他的資料結構如下圖所示:
ByteBuf資料結構

他有三種使用模式:

1.Heap Buffer 堆緩衝區
堆緩衝區是ByteBuf最常用的模式,他將資料儲存在堆空間。

2.Direct Buffer 直接緩衝區
直接緩衝區是ByteBuf的另外一種常用模式,他的記憶體分配都不發生在堆,jdk1.4引入的nio的ByteBuffer類允許jvm通過本地方法呼叫分配記憶體,這樣做有兩個好處

通過免去中間交換的記憶體拷貝, 提升IO處理速度; 直接緩衝區的內容可以駐留在垃圾回收掃描的堆區以外。
DirectBuffer 在 -XX:MaxDirectMemorySize=xxM大小限制下, 使用 Heap 之外的記憶體, GC對此”無能為力”,也就意味著規避了在高負載下頻繁的GC過程對應用執行緒的中斷影響.

3.Composite Buffer 複合緩衝區
複合緩衝區相當於多個不同ByteBuf的檢視,這是netty提供的,jdk不提供這樣的功能。

除此之外,他還提供一大堆api方便你使用,在這裡我就不一一列出了,具體參見ByteBuf位元組快取。

Codec
Netty中的編碼/解碼器,通過他你能完成位元組與pojo、pojo與pojo的相互轉換,從而達到自定義協議的目的。
在Netty裡面最有名的就是HttpRequestDecoder和HttpResponseEncoder了。

參考自簡書-連結:https://www.jianshu.com/p/b9f3f6a16911