Netty入門與實戰——服務端源碼及啓動流程

此係列文章來源於總結歸納Netty 入門與實戰:仿寫微信 IM 即時通訊系統

代碼:

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.AttributeKey;

public class NettyServer {

    private static final int BEGIN_PORT = 8000;

    public static void main(String[] args) {
        NioEventLoopGroup boosGroup = new NioEventLoopGroup();    //創建新連接
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();  //讀取數據以及業務邏輯處理

        final ServerBootstrap serverBootstrap = new ServerBootstrap();   //引導類,進行服務端的啓動工作
        final AttributeKey<Object> clientKey = AttributeKey.newInstance("clientKey");
        serverBootstrap
                .group(boosGroup, workerGroup)   //給引導類配置兩大線程組(線程模型)
                .channel(NioServerSocketChannel.class)   //指定IO模型爲NIO
                .attr(AttributeKey.newInstance("serverName"), "nettyServer")  //給NioServerSocketChannel指定一些自定義屬性,通過channel.attr()取出這個屬性
                .childAttr(clientKey, "clientValue")  //給每一條連接指定自定義屬性
                .option(ChannelOption.SO_BACKLOG, 1024)//表示系統用於臨時存放已完成三次握手的請求的隊列的最大長度
                .childOption(ChannelOption.SO_KEEPALIVE, true)//是否開啓TCP底層心跳機制,true爲開啓
                .childOption(ChannelOption.TCP_NODELAY, true)//是否開啓Nagle算法,true表示關閉,false表示開啓,通俗地說,如果要求高實時性,有數據發送時就馬上發送,就關閉,如果需要減少發送次數減少網絡交互,就開啓。
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    protected void initChannel(NioSocketChannel ch) {
                        System.out.println(ch.attr(clientKey).get());
                    }
                });   //定義後續每條連接的數據讀寫,業務處理邏輯


        bind(serverBootstrap, BEGIN_PORT);   //遞增綁定端口
    }

    private static void bind(final ServerBootstrap serverBootstrap, final int port) {
        serverBootstrap.bind(port).addListener(future -> {
            if (future.isSuccess()) {
                System.out.println("端口[" + port + "]綁定成功!");
            } else {
                System.err.println("端口[" + port + "]綁定失敗!");
                bind(serverBootstrap, port + 1);
            }
        });
    }
}

解析:

*首先創建了兩個NioEventLoopGroup,這兩個對象可以看做是傳統IO編程模型的兩大線程組,bossGroup表示監聽端口,accept 新連接的線程組,workerGroup表示處理每一條連接的數據讀寫的線程組。類比爲:一個工廠要運作,必然要有一個老闆負責從外面接活,然後有很多員工,負責具體幹活,老闆就是bossGroup,員工們就是workerGroupbossGroup接收完連接,扔給workerGroup去處理。

*然後創建了一個引導類 ServerBootstrap的對象,這個類將引導我們進行服務端的啓動工作

*通過.group(bossGroup, workerGroup)給引導類配置兩大線程組,指定引導類的線程模型

*通過.channel(NioServerSocketChannel.class)來指定 IO 模型

*調用childHandler()方法,給這個引導類創建一個ChannelInitializer,定義後續每條連接的數據讀寫,業務處理邏輯

*ChannelInitializer這個類中,NioSocketChannel就是 Netty 對 NIO 類型的連接的抽象,前面NioServerSocketChannel也是對 NIO 類型的連接的抽象

*遞增地綁定端口,起始端口號BEGIN_PORT=8000,若綁定失敗則端口號+1,直到綁定端口成功

總結:

1、創建一個引導類,然後給他指定線程模型,IO模型,連接讀寫處理邏輯,綁定端口之後,服務端就啓動起來了。

2、bind 方法是異步的,我們可以通過這個異步機制來實現端口遞增綁定。

3、Netty 服務端啓動額外的參數,主要包括給服務端 Channel 或者客戶端 Channel 設置屬性值,設置底層 TCP 參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章