• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • Netty網絡框架

    buffer[緩沖區]; S2[Channel的flush方法] --發送緩沖區中的數據并清空--> buffer[緩沖區]; buffer --發送--> S3[SocketChannel];
    write():將數據寫入到緩沖區
    flush():發送緩沖區中的數據并進行清空
    writeAndFlush():將數據寫入到緩沖區,同時發送緩沖區中的數據并進行清空
    

    Channel的writeAndFlush()和flush()方法會從鏈表的最后一個節點開始從后往前尋找有OUT性質的Handler進行處理。

    ChannelHandlerContext的writeAndFlush()和flush()方法會從當前節點從后往前尋找有OUT性質的Handler進行處理。

    關于寫就緒事件

    當SocketChannel可以寫入數據時,將會觸發寫就緒事件,所以一般不能隨便監聽,否則將會一直觸發。

    當SocketChannel在寫入數據寫不進時(緩沖區已經滿了),向Selector傳遞要監聽此Channel的寫就緒事件,然后強制發送緩沖區中的數據并進行清空,此時將會觸發寫就緒事件,當Selector處理完寫就緒事件后,應當剔除監聽此Channel的寫就緒事件。

    為什么說Netty中的所有操作都是異步的

    Channel中的所有任務都會放入到其綁定的EventLoop的任務隊列中,然后等待被EventLoop中的線程處理。

    關于ChannelFuture

    由于Netty中的所有操作都是異步的,因此一般會返回ChannelFuture對象,用于存儲Channel異步執行的結果。

    當創建ChannelFuture實例時,isDone()方法返回false,僅當ChannelFuture被設置成成功或者失敗時,isDone()方法才返回true。

    可以往ChannelFuture中添加ChannelFutureListener,當任務被執行完畢后由IO線程自動調用。


    Netty中的ByteBuf

    ByteBuf有readerIndex和writerIndex兩個指針,默認都為0,當進行寫操作時移動writerIndex指針,讀操作時移動readerIndex指針。

    可讀容量 = writerIndex - readerIndex

    *只有read()/write()方法才會移動指針,get()/set()方法不會移動指針。

    *ByteBuf支持動態擴容。

    ByteBuf的創建和管理

    使用ByteBufAllocator來創建和管理ByteBuf,其分別提供PooledByteBufAllocator和UnpooledByteBufAllocator實現類,分別代表池化和非池化。

    *Netty同時也提供了Pooled和Unpooled工具類來創建和管理ByteBuf。

    池化的ByteBuf(Pooled)

    每次使用時都從池中取出一個ByteBuf對象,當使用完畢后再放回到池中。

    每個ByteBuf都有一個refCount屬性,僅當refCount屬性為0時才將ByteBuf對象放回到池中。

    ByteBuf的release()方法可以使refCount屬性減1(一般由最后一個訪問ByteBuf的Handler進行處理)

    非池化的ByteBuf(Unpooled)

    每次使用時都創建一個新的ByteBuf對象。

    使用池化ByteBuf的風險

    如果每次使用ByteBuf后卻不進行釋放,那么有可能發生內存泄漏,對象池中會不停的創建ByteBuf對象。

    非池化的ByteBuf對象能夠依賴JVM自動進行回收。

    關于堆內和堆外的ByteBuf

    池化和非池化的ByteBufAllocator中都可以創建堆內和堆外的ByteBuf對象。

    堆外的ByteBuf可以避免在進行IO操作時數據從堆內內存復制到操作系統內存的過程,所以對于IO操作來說一般使用堆外的ByteBuf,而對于內部業務數據處理來說使用堆內的ByteBuf。


    Netty支持的IO模型

    Netty支持BIO、NIO、AIO三種IO模型。

    *其中AIO模型只在Netty的5.x版本有提供,但不建議使用,因為Netty不再維護同時也廢除了5.x版本,其原因是在Linux中AIO比NIO強不了多少。

    Netty如何切換IO模型

    只需要將EventLoopGroup和ServerSocketChannel換成相應IO模型的API即可。


    Netty中使用Reactor模式

    Reactor單線程模式

    EventLoopGroup eventLoopGroup = new NioEventLoopGroup(1);
    

    Reactor多線程模式

    EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
    

    *默認CPU核數 x 2個EventLoop。

    主從Reactor多線程模式

    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    

    關于TCP的粘包和半包

    粘包(多個數據包被合并成一個進行發送)

    graph LR; data1[ABC] --> compact[ABCDEF]; data2[DEF] --> compact; compact --send--> net[網絡]

    半包(一個數據包被拆分成多個進行發送)

    graph LR; data1[ABCDEF] --> part1[ABC]; data1 --> part2[DEF]; part1 --send--> net1[網絡]; part2 --send--> net2[網絡];

    發生粘包的原因

    1.寫入的數據遠小于緩沖區的大小,TCP協議為了性能的考慮,合并后再進行發送。

    發生半包的原因

    1.寫入的數據大于緩沖區的大小,因此必須拆包后再進行傳輸(緩沖區已滿,強制flush)

    2.寫入的數據大于協議的MTU(最大傳輸單元),因此必須拆包后再進行傳輸。

    TCP長連接的缺陷

    長連接中可以發送多個請求,同時TCP協議是流式協議,消息無邊界,所以有一個很棘手的問題,接收方怎么去知道一個請求中的數據到底是哪里到哪里,以及一個請求中的數據有可能是粘包后的結果,同時多個請求中的數據有可能是半包后的結果。

    解決方案

    1.使用短連接,連接開始和連接結束之間的數據就是請求的數據。

    2.使用固定的長度,每個請求中的數據都使用固定的長度,接收方以接收到固定長度的數據來確定一個完整的請求數據。

    3.使用指定的分隔符,每個請求中的數據的末尾都加上一個分隔符,接收方以分隔符來確定一個完整的請求數據。

    4.使用特定長度的字段去存儲請求數據的長度,接收方根據請求數據的長度來確定一個完整的請求數據。

    Netty對TCP長連接缺陷的解決方案

    FixedLengthFrameDecoder:使用固定的長度
    
    DelimiterBasedFrameDecoder:使用指定的分隔符
    
    LengthFieldBasedFrameDecoder:使用特定長度的字段去存儲請求數據的長度
    

    關于TCP的KeepAlive

    正常情況下雙方建立連接后是不會斷開的,KeepAlive就是防止連接雙方中的任意一方由于意外斷開而通知不到對方,導致對方一直持有連接,占用資源。

    *建立連接需要三次握手、正常斷開連接需要四次揮手。

    KeepAlive有三個核心參數

    net.ipv4.tcp_keepalive_timeout:連接的超時時間(默認7200s)
    
    net.ipv4.tcp_keepalive_intvl:發送探測包的間隔(默認75s)
    
    tnet.ipv4.cp_keepalive_probes:發送探測包的個數(默認9個)
    

    這三個參數都是系統參數,會影響部署在機器上的所有應用。

    KeepAlive的開關是在應用層開啟的,只有當應用層開啟了KeepAlive,KeepAlive才會生效。

    java.net.Socket.setKeepAlive(boolean on);
    

    當連接在指定時間內沒有發送請求時,開啟KeepAlive的一端就會向對方發送一個探測包,如果對方沒有回應,則每隔指定時間發送一個探測包,總共發送指定個探測包,如果對方都沒有回應則認為對方不可用,斷開連接。

    為什么要做應用層的KeepAlive

    1.KeepAlive參數是系統參數,對于應用來說不夠靈活。

    2.默認檢測一個不可用的連接所需要的時間太長。

    怎么做應用層的KeepAlive

    1.定時任務

    客戶端定期向所有已經建立連接的服務端發送心跳檢測,如果服務端連續沒有回應指定個心跳檢測,則認為對方不可用,此時客戶端應該重連。

    服務端定期向所有已經建立連接的客戶端發送心跳檢測,如果客戶端連續沒有回應指定個心跳檢測,則認為對方不可用,此時應該斷開連接。

    2.計時器

    連接在指定時間內沒有發送請求則認為對方不可用

    Netty對KeepAlive的支持

    Netty開啟KeepAlive

    Bootstrap.option(ChannelOption.SO_KEEPALIVE,true);
    ServerBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);
    

    Netty提供的KeepAlive機制

    Netty提供的IdleStateHandler能夠檢測處于Idle狀態的連接。

    Idle狀態類型

    reader_idle:SocketChannel在指定時間內都沒有數據可讀
    
    writer_idle:SocketChannel在指定時間內沒有寫入數據
    
    all_idle:SocketChannel在指定時間內沒有數據可讀或者沒有寫入數據
    

    直接將IdleStateHandler添加到ChannelPipeline即可,當Netty檢測到處于Idle狀態的連接時,將會自動調用其Handler的userEventTriggered()方法,用戶只需要在該方法中判斷Idle狀態的類型,然后做出相應的處理。

    關于HTTP的KeepAlive

    HTTP的KeepAlive是對長連接和短連接的選擇,并不是保持連接存活的一種機制。

    HTTP是基于請求和響應的,客戶端發送請求給服務端然后等待服務端的響應,當服務端檢測到請求頭中包含Connection:KeepAlive時,表示客戶端使用長連接,此時服務端應該保持連接,當檢測到請求頭中包含Connection:close時,表示客戶端使用短連接,此時服務端應該主動斷開連接。

    TCP并不是基于請求和響應的,客戶端可以發送請求給服務端,同時服務端也可以發送請求給客戶端。

    版權聲明:本文為weixin_45714179原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/weixin_45714179/article/details/103387137

    智能推薦

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    猜你喜歡

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    基于TCP/IP的網絡聊天室用Java來實現

    基于TCP/IP的網絡聊天室實現 開發工具:eclipse 開發環境:jdk1.8 發送端 接收端 工具類 運行截圖...

    19.vue中封裝echarts組件

    19.vue中封裝echarts組件 1.效果圖 2.echarts組件 3.使用組件 按照組件格式整理好數據格式 傳入組件 home.vue 4.接口返回數據格式...

    劍指Offer39-調整數組順序使奇數位于偶數前面

    一開始想著用冒泡排序的方法來做,但是bug還是很多,后來看了評論區答案,發現直接空間換時間是最簡單的,而且和快排的寫法是類似的。...

    【一只蒟蒻的刷題歷程】【藍橋杯】歷屆試題 九宮重排 (八數碼問題:BFS+集合set)

    資源限制 時間限制:1.0s 內存限制:256.0MB 問題描述 如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。 我們把第一個圖的局面記為:12345678. 把第二個圖的局面記為:123.46758 顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。 本題目的任務是已知九宮的初態...

    精品国产乱码久久久久久蜜桃不卡