Netty引導(dǎo)客戶端和無(wú)連接協(xié)議

2018-08-08 10:44 更新

Bootstrap類可以用來(lái)引導(dǎo)客戶端和一些無(wú)連接協(xié)議,在本節(jié)中,我們將回顧可用的各種方法引導(dǎo)客戶端,引導(dǎo)線程,和可用的管道實(shí)現(xiàn)。

客戶端引導(dǎo)方法

下表是 Bootstrap 的常用方法,其中很多是繼承自 AbstractBootstrap。

Table 9.1 Bootstrap methods

名稱描述
group設(shè)置 EventLoopGroup 用于處理所有的 Channel 的事件
channel channelFactorychannel() 指定 Channel 的實(shí)現(xiàn)類。如果類沒(méi)有提供一個(gè)默認(rèn)的構(gòu)造函數(shù),你可以調(diào)用 channelFactory() 來(lái)指定一個(gè)工廠類被 bind() 調(diào)用。
localAddress指定應(yīng)該綁定到本地地址 Channel。如果不提供,將由操作系統(tǒng)創(chuàng)建一個(gè)隨機(jī)的。或者,您可以使用 bind() 或 connect()指定localAddress
option設(shè)置 ChannelOption 應(yīng)用于 新創(chuàng)建 Channel 的 ChannelConfig。這些選項(xiàng)將被 bind 或 connect 設(shè)置在通道,這取決于哪個(gè)被首先調(diào)用。這個(gè)方法在創(chuàng)建管道后沒(méi)有影響。所支持 ChannelOption 取決于使用的管道類型。請(qǐng)參考9.6節(jié)和 ChannelConfig 的 API 文檔 的 Channel 類型使用。
attr這些選項(xiàng)將被 bind 或 connect 設(shè)置在通道,這取決于哪個(gè)被首先調(diào)用。這個(gè)方法在創(chuàng)建管道后沒(méi)有影響。請(qǐng)參考9.6節(jié)。
handler設(shè)置添加到 ChannelPipeline 中的 ChannelHandler 接收事件通知。
clone創(chuàng)建一個(gè)當(dāng)前 Bootstrap的克隆擁有原來(lái)相同的設(shè)置。
remoteAddress設(shè)置遠(yuǎn)程地址。此外,您可以通過(guò) connect() 指定
connect連接到遠(yuǎn)端,返回一個(gè) ChannelFuture, 用于通知連接操作完成
bind將通道綁定并返回一個(gè) ChannelFuture,用于通知綁定操作完成后,必須調(diào)用 Channel.connect() 來(lái)建立連接。

如何引導(dǎo)客戶端

Bootstrap 類負(fù)責(zé)創(chuàng)建管道給客戶或應(yīng)用程序,利用無(wú)連接協(xié)議和在調(diào)用 bind() 或 connect() 之后。

下圖展示了如何工作

Figure%209

  1. 當(dāng) bind() 調(diào)用時(shí),Bootstrap 將創(chuàng)建一個(gè)新的管道, 當(dāng) connect() 調(diào)用在 Channel 來(lái)建立連接
  2. Bootstrap 將創(chuàng)建一個(gè)新的管道, 當(dāng) connect() 調(diào)用時(shí)
  3. 新的 Channel

Figure 9.2 Bootstrap process

下面演示了引導(dǎo)客戶端,使用的是 NIO TCP 傳輸

Listing 9.1 Bootstrapping a client

EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap(); //1
bootstrap.group(group) //2
    .channel(NioSocketChannel.class) //3
    .handler(new SimpleChannelInboundHandler<ByteBuf>() { //4
        @Override
        protected void channeRead0(
            ChannelHandlerContext channelHandlerContext,
            ByteBuf byteBuf) throws Exception {
                System.out.println("Received data");
                byteBuf.clear();
            }
        });
ChannelFuture future = bootstrap.connect(
    new InetSocketAddress("www.manning.com", 80)); //5
future.addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture channelFuture)
        throws Exception {
            if (channelFuture.isSuccess()) {
                System.out.println("Connection established");
            } else {
                System.err.println("Connection attempt failed");
                channelFuture.cause().printStackTrace();
            }
        }
    });
  1. 創(chuàng)建一個(gè)新的 Bootstrap 來(lái)創(chuàng)建和連接到新的客戶端管道
  2. 指定 EventLoopGroup
  3. 指定 Channel 實(shí)現(xiàn)來(lái)使用
  4. 設(shè)置處理器給 Channel 的事件和數(shù)據(jù)
  5. 連接到遠(yuǎn)端主機(jī)

注意 Bootstrap 提供了一個(gè)“流利”語(yǔ)法——示例中使用的方法(除了connect()) 由 Bootstrap 返回實(shí)例本身的引用鏈接他們。

兼容性

Channel 的實(shí)現(xiàn)和 EventLoop 的處理過(guò)程在 EventLoopGroup 中必須兼容,哪些 Channel 是和 EventLoopGroup 是兼容的可以查看 API 文檔。經(jīng)驗(yàn)顯示,相兼容的實(shí)現(xiàn)一般在同一個(gè)包下面,例如使用NioEventLoop,NioEventLoopGroup 和 NioServerSocketChannel 在一起。請(qǐng)注意,這些都是前綴“Nio”,然后不會(huì)用這些代替另一個(gè)實(shí)現(xiàn)和另一個(gè)前綴,如“Oio”,也就是說(shuō) OioEventLoopGroup 和NioServerSocketChannel 是不相容的。

Channel 和 EventLoopGroup 的 EventLoop 必須相容,例如NioEventLoop、NioEventLoopGroup、NioServerSocketChannel是相容的,但是 OioEventLoopGroup 和 NioServerSocketChannel 是不相容的。從類名可以看出前綴是“Nio”的只能和“Nio”的一起使用。

EventLoop 和 EventLoopGroup

記住,EventLoop 分配給該 Channel 負(fù)責(zé)處理 Channel 的所有操作。當(dāng)你執(zhí)行一個(gè)方法,該方法返回一個(gè) ChannelFuture ,它將在 分配給 Channel 的 EventLoop 執(zhí)行。

EventLoopGroup 包含許多 EventLoops 和分配一個(gè) EventLoop 通道時(shí)注冊(cè)。我們將在15章更詳細(xì)地討論這個(gè)話題。

清單9.2所示的結(jié)果,試圖使用一個(gè) Channel 類型與一個(gè) EventLoopGroup 兼容。

Listing 9.2 Bootstrap client with incompatible EventLoopGroup

EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap(); //1
bootstrap.group(group) //2
    .channel(OioSocketChannel.class) //3
    .handler(new SimpleChannelInboundHandler<ByteBuf>() { //4
        @Override
        protected void channelRead0(
            ChannelHandlerContext channelHandlerContext,
                    ByteBuf byteBuf) throws Exception {
                System.out.println("Reveived data");
                byteBuf.clear();
            }
        });
ChannelFuture future = bootstrap.connect(
    new InetSocketAddress("www.manning.com", 80)); //5
future.syncUninterruptibly();
  1. 創(chuàng)建新的 Bootstrap 來(lái)創(chuàng)建新的客戶端管道
  2. 注冊(cè) EventLoopGroup 用于獲取 EventLoop
  3. 指定要使用的 Channel 類。通知我們使用 NIO 版本用于 EventLoopGroup , OIO 用于 Channel
  4. 設(shè)置處理器用于管道的 I/O 事件和數(shù)據(jù)
  5. 嘗試連接到遠(yuǎn)端。當(dāng) NioEventLoopGroup 和 OioSocketChannel 不兼容時(shí),會(huì)拋出 IllegalStateException 異常

IllegalStateException 顯示如下:

Listing 9.3 IllegalStateException thrown because of invalid configuration

Exception in thread "main" java.lang.IllegalStateException: incompatible event loop
type: io.netty.channel.nio.NioEventLoop
at
io.netty.channel.AbstractChannel$AbstractUnsafe.register(AbstractChannel.java:5
71)
...

出現(xiàn) IllegalStateException 的其他情況是,在 bind() 或 connect() 調(diào)用前 調(diào)用需要設(shè)置參數(shù)的方法調(diào)用失敗時(shí),包括:

  • group()
  • channel() 或 channnelFactory()
  • handler()

handler() 方法尤為重要,因?yàn)檫@些 ChannelPipeline 需要適當(dāng)配置。 一旦提供了這些參數(shù),應(yīng)用程序?qū)⒊浞掷?Netty 的能力。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)