1. 程式人生 > >Netty從沒聽過到入門 -- 服務器端詳解

Netty從沒聽過到入門 -- 服務器端詳解

是你 too code inb 線程 ace IT 線程池 fin

本文僅適用與Netty4.0.32版本,其他版本是否適用表示並不清楚...

Netty服務器啟動流程:

1、創建線程池

創建處理連接的線程池:bossGroup
創建處理所有事件的線程池:workerGroup

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

2、設定輔助啟動類。ServerBootStrap
傳入1中開辟的線程池
指定連接該服務器的channel類型
指定需要執行的childHandler
設置部分參數,如AdaptiveRecvByteBufAllocator緩存大小
.Option用於設置bossGroup相關參數
.childOption用於設置workerGroup相關參數


2.5、此處可處理一個問題:超長字符串在服務端handler無法被一次接收完
可通過此句進行設置:.childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(64, MAX_LENGTH_OF_MSG, 65536))

技術分享圖片
    ServerBootstrap serverBootstrap = new ServerBootstrap();
    serverBootstrap.group(bossGroup, workerGroup)
    .channel(NioServerSocketChannel.class)//設置channel類型
    .childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(64, MAX_LENGTH_OF_MSG, 65536))
    .childHandler(new childChannelHandler());//選擇執行handler
技術分享圖片

此處的MAX_LENGTH_OF_MSG必須為2的次冪,不然肯定不會是你設置的那個值,具體會變成什麽,源碼還沒看,等看了再補充...

2.75、構建Handler處理流程

  樣例如下:

技術分享圖片
public class childChannelHandler extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            //TODO 添加各種功能handler 消息加解密,消息規範檢測,構建返回碼
            ch.pipeline().addLast(new NettyServerHandler());
        }
    }
技術分享圖片

  當要添加多個handler時,就必須註意添加的順序。

  這裏的handler分為兩種類型:

    一種繼承ChannelInboundHandler,用於處理來自客戶端的消息,比如對客戶端的消息進行解碼,讀取等等。該類型在pipeline中的執行順序與添加順序一致。

    一種繼承ChannelOutboundHandler,用於處理即將發往客戶端的消息,比如對該消息進行編輯,編碼等等。該類型在pipeline中的執行順序與添加順序相反。

  而且ChannelOutboundHandler的所有handler,放在ChannelInboundHandler下面是執行不到的。

比如:

技術分享圖片
public class childChannelHandler extends ChannelInitializer<SocketChannel>{
        @Override
        public void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new OutboundHandler1());  //handler1
            ch.pipeline().addLast(new OutboundHandler2());  //handler2
            ch.pipeline().addLast(new InboundHandler1());   //handler3
            ch.pipeline().addLast(new InboundHandler2());   //handler4
        }
    }
技術分享圖片

  以上4個handler的實際執行順序分別為handler3 -> handler4 -> handler2 ->handler1

  如果在handler4下方加上OutboundHandler3,那麽這個handler是不會被執行到的。


3、同步等待綁定指定端口
此處可多次執行bind語句綁定多個端口

    ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
    channelFuture = serverBootstrap.bind(8081).sync();
    ...    

4、同步等待服務器關閉信息

  channelFuture.channel().closeFuture().sync();

5、最後關閉此前開辟的兩個線程池

  bossGroup.shutdownGracefully();
  workerGroup.shutdownGracefully();

最後整段服務器代碼如下:

技術分享圖片
package Netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.AdaptiveRecvByteBufAllocator;


public class NettyServer {
    public void startServerInPort(int port) throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try{
            //設置啟動輔助類
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
            .channel(NioServerSocketChannel.class)//設置channel類型
            .childOption(ChannelOption.RCVBUF_ALLOCATOR, new AdaptiveRecvByteBufAllocator(64, 2048, 65536))
            .childHandler(new childChannelHandler());//選擇執行handler
            
            //阻塞等待服務器完全啟動
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            
            channelFuture.channel().closeFuture().sync();
        }finally{
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
    public class childChannelHandler extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            //TODO 添加各種功能handler 消息加解密,消息規範檢測,構建返回碼
            ch.pipeline().addLast(new NettyServerHandler());
        }
    }
}
技術分享圖片

客戶端的這部分代碼和服務器端差不多,就不另開一文啰嗦了。之間貼代碼:

技術分享圖片
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class NettyClient {
    
    public void sendMsgToServer() throws Exception{
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            //設置輔助啟動類信息
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
            .channel(NioSocketChannel.class)//選擇channel類型
            .option(ChannelOption.TCP_NODELAY, true)
            .handler(new childChannelHandler());
            
            //阻塞等待成功連接服務器
            ChannelFuture channelFuture = bootstrap.connect(localhost,8000).sync();
            
            //阻塞等待來自服務器的處理結果
            channelFuture.channel().closeFuture().sync();
        }finally{
            group.shutdownGracefully();
        }
    }
    
    private class childChannelHandler extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            //TODO 添加其他功能處理Handler,如消息加解密
            ch.pipeline().addLast(new NettyClientHandler());
        }
    }

}
技術分享圖片

Netty從沒聽過到入門 -- 服務器端詳解