源码阅读之Netty启动流程

Netty线程模型


15854876-607a7e78d1378b6b.png
主从Reactor多线程.png

Boss服务端


15854876-e38c15584fa34cf1.png
Boss EventLoopGroup.png

Netty客户端


15854876-714a3eb338449264.png
Worker EventLoopGroup.png

主要启动流程


15854876-fb8eff47736df53f.png
启动流程.png

1.传统阻塞Nio的实现步骤
服务端
①创建Selector
②创建ServerSocketChannel,并配置参数(包括设置为非阻塞,绑定到指定端口,bind())
③将channel注册到Selector上,并声明感兴趣的事件
④阻塞等待,遍历Selector持有的selectKeys,对相应的连接,读,写事件进行处理

客户端
①创建Selector
②创建SocketChannel,并配置参数(包括设置为非阻塞,向指定地址和端口发起连接connect())
③将channel注册到Selector上,并声明感兴趣的事件
④阻塞等待,遍历Selector持有的selectKeys,对相应的连接,读,写事件进行处理

我们可以总结为以下几点
1.创建通道,设置通道为非阻塞(其实可以看作一条通道相当于一个连接)
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
2.创建选择器
selector = Selector.open();
3.注册感兴趣的事件
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
4.把通道注册到选择器
sc.register(selector, interestSet, new Buffers(256, 256));
5.阻塞等待,selector遍历每个已就绪的通道,处理这个通道已就绪的事件
selector.select();
/Set中的每个key代表一个通道/
Set<SelectionKey> keySet = selector.selectedKeys();
Iterator<SelectionKey> it = keySet.iterator();
6.对感兴趣的事件进行处理
while(it.hasNext()){
key = it.next();
if(key.isAcceptable()){}
if(key.isReadable()){}
if(key.isWritable()){}
}

/通过SelectionKey获取对应的通道/
Buffers buffers = (Buffers)key.attachment();
ByteBuffer readBuffer = buffers.getReadBuffer();
ByteBuffer writeBuffer = buffers.gerWriteBuffer();
/通过SelectionKey获取通道对应的缓冲区/
SocketChannel sc = (SocketChannel) key.channel();
/表示底层socket的读缓冲区有数据可读/
if(key.isReadable()){
/从socket的读缓冲区读取到程序定义的缓冲区中/
sc.read(readBuffer);
readBuffer.flip();
/字节到utf8解码/
CharBuffer cb = utf8.decode(readBuffer);
/显示接收到由服务器发送的信息/
System.out.println(cb.array());
readBuffer.clear();
}

我们再来看Netty是进行了哪些封装

Netty的抽象流程图


15854876-8b91681be710e797.png
Netty抽象流程图.png

netty的几大关键组件
1.NioEventLoopGroup
主要用于创建线程池,用于执行任务(可以是监听端口或者进行业务处理,即我们平时创建的boss和worker)

2.Channel
代表了一条连接,netty对java的SocketChannel 进行了封装

3.ByteBuf
缓冲区,数据载体

4.ChannelHandler
具体的业务处理器,我们可以自定义,也可以使用netty以及提供的如,编解码处理器

5.Pipeline
pipeline和channel是一一对应的,一个pipeline包含一个或多个ChannelHandler,各个ChannelHandler之间以双向链表的方式进行连接,主要便于事件传播.

Channel


15854876-cb04ef7ca322a910.png
channel继承关系图.png

AbstractChannel的构造函数

protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}

AbstractNioChannel的构造函数
主要做一些初始化channel以及其它

ch.configureBlocking(false);

设置为非阻塞方式

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
super(parent);
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
ch.configureBlocking(false);
} catch (IOException e) {
try {
ch.close();
} catch (IOException e2) {
if (logger.isWarnEnabled()) {
logger.warn(
"Failed to close a partially initialized socket.", e2);
}
}

    throw new ChannelException("Failed to enter non-blocking mode.", e);
}

}

AbstractNioByteChannel的构造函数
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
super(parent, ch, SelectionKey.OP_READ);
}
我们看到注册了一个 SelectionKey.OP_READ 事件,主要关心数据读写事件

NioServerSocketChannel的构造函数

public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}

我们可以看到有一个 SelectionKey.OP_ACCEPT,主要关心新连接事件

猜你喜欢

转载自blog.csdn.net/weixin_34023982/article/details/87550343