打卡日期(2019-07-03)
netty流程中涉及到的重要組件
- channel:通道,相當於連接
- channelHandler:通道處理器,類似於處理器,攔截器這樣的概念。當請求過來之後,會一個一個的通過channelHandler來得到一個個的處理器,處理之後交給業務方法完成真正的處理,然後按照相反的順序進行原路返回
- pipeLine:管道,一個PipeLine是由多個channelHandler構成的。請求過來的時候,會通過一個個的處理器沿着管道不斷的往前走
結合例子來說明執行流程
package com.dragon.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @Auther: lijianlong
* @Date: 2019/7/3 17:44
* @Description:
*/
public class Server {
public static void main(String[] args) throws InterruptedException {
//事件循環組 acceptorGroup用於接收請求
EventLoopGroup acceptorGroup = new NioEventLoopGroup();
//事件循環組 handlerGroup用於處理請求
EventLoopGroup handlerGroup = new NioEventLoopGroup();
try{
// sub-class which allows easy bootstrap of 用於輕鬆的啓動bootstrap
ServerBootstrap serverBootstrap = new ServerBootstrap()
// group (acceptorGroup,handlerGroup)
// acceptorGroup which is used for the parent (acceptor) 用於接收所有的請求
// handlerGroup are used to handle all the events and IO 處理所有的事件和IO操作
.group(acceptorGroup,handlerGroup)
// NioSctpServerChannel 利用nio模式接收一個新的連接創建NioSctpChannel
.channel(NioServerSocketChannel.class)
// 自定義處理器
.childHandler(new InitServer());
//綁定80端口,端口號可以自定義
ChannelFuture future = serverBootstrap.bind(80).sync();
future.channel().closeFuture().sync();
}finally {
//友好關閉兩個線程組
acceptorGroup.shutdownGracefully();
handlerGroup.shutdownGracefully();
}
}
}
package com.dragon.netty;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
* @Auther: lijianlong
* @Date: 2019/7/3 17:53
* @Description: 初始化器
*/
public class InitServer extends ChannelInitializer<SocketChannel>{
/**
* 一旦channel管道被註冊這個方法就會被調用,這個方法返回一個之後實例將會從ChannelPipeline移除channel
*/
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// 在次SocketChannel管道的位置增追加一個通道處理器
ch.pipeline().addLast("httpServerCodec",new HttpServerCodec());
// 在管道的最後一個位置追加自己的通道處理器
ch.pipeline().addLast("myHandler",new MyHandler());
}
}
package com.dragon.netty;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
/**
* @Auther: lijianlong
* @Date: 2019/7/3 18:05
* @Description: 自定義處理器
*/
public class MyHandler extends SimpleChannelInboundHandler<HttpObject> {
/**
* <strong>這個方法將會在5.0中改名爲messageReceived
* @param ctx 這個ChannelHandlerContext屬於 SimpleChannelInboundHandler處理器
* @param msg 待處理的消息
* @throws Exception is thrown if an error occurred
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if(msg instanceof HttpRequest){
System.out.println("接收到一個請求");
//向返回的內容
ByteBuf context = Unpooled.copiedBuffer("Hello Word", CharsetUtil.UTF_8);
//構造一個repsone
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,context);
response.headers()
// 設置返回類型
.set(HttpHeaderNames.CONTENT_TYPE,"text/plain")
// 設置返回多少字節 content-length
.set(HttpHeaderNames.CONTENT_LENGTH,context.readableBytes());
// write 只會將返回信息寫入到緩存當中
//ctx.write(response);
//writeAndFlush 將消息寫入緩存併發送到客戶端之後清空緩存
ctx.writeAndFlush(response);
}
}
}
啓動Server服務器:
通過瀏覽器訪問:http://localhost
響應:hello word
netty的執行流程
結合上面的代碼梳理一下netty的執行流程
- 1.創建ServerBootStrap實例
- 2.設置並綁定Reactor線程池:EventLoopGroup,EventLoop就是處理所有註冊到本線程的多路複用器(Selector)上面的Channel
- 3.設置並綁定服務端的Channel
- 4.創建處理網絡事件的ChannelPipeLine和Handler,網絡事件以流的形式在其中流傳,handler完成多數的功能定製,比如編解碼等SSL安全認證
- 5.綁定並啓動監聽端口
- 6.當輪詢到準備就緒的Channel以後,由Reactor線程:NioEventLoop執行PipeLine中的方法,最終調用並執行channelHandler