Netty学习(二):Netty的核心组件
作者:互联网
学习Netty有一个很大的苦难点就是关于Netty有一大堆的专有名词,如果不懂这些专有名词的意思,就很难读懂源码和理解Netty的流程。
一、Netty的核心组件(慢慢补充)
一.ByteBuf(缓冲区,Netty 的数据容器)
buffer中文名又叫缓冲区,是”在数据传输时,在内存里开辟的一块临时保存数据的区域”。它其实是一种化同步为异步的机制,可以解决数据传输的速率不对等以及不稳定的问题。
根据这个定义,我们可以知道,在涉及IO的地方,基本都会有Buffer存在,最常见的就是JAVA IO操作文件的读取和写入,outputStream.write()只将内容写入了buffer,必须调用outputStream.flush(),才能保证数据写入生效。
二.Channel(通道,连接)
Channel 是 Java NIO 的一个基本构造。
它代表一个到实体( 如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或者多个不同的I/O操作的程序组件) 的开放连接,如读操作和写操作
目前,可以把 Channel 看作是传入(入站)或者传出(出站)数据的载体。因此,它可以被打开或者被关闭,连接或者断开连接。
1、ServerSocketChannel (客户端和引导服务器信道)
连接客户端和引导服务器的信道
2、SocketChannel(引导服务器和工作服务器信道)
客户端和工作服务器的信道,将引导服务器将客户转交给工作服务器。
3、ChannelHandler(消息处理器)
ChannelHandler 是消息的具体处理器,主要负责处理客户端/服务端接收和发送的数据。
4、ChannelPipeline( 消息处理器的容器)
ChannelPipeline是ChannelHandler 的容器,将不同的消息处理器放入其中。
三.EventLoop 和EventLoopGroup (事件轮询器和事件轮询器群,控制流、多线程处理、并发 )
当一个连接到达时,Netty 就会注册一个 Channel,然后从 EventLoopGroup 中分配一个 EventLoop 绑定到这个 Channel 上,在该 Channel 的整个生命周期中都是有这个绑定的 EventLoop 来服务的。
四.ServerBootstrap(引导服务器)
Netty采用了Reactor模型,引导服务器为Netty服务器的入口。
二、Netty服务端代码示例
我用比较通俗的方式来描述一下Netty服务端代码流程,因为存在异步方法,所以代码的执行并不完全是我们看到的顺序,我由上到下进行介绍。
以海底捞举例,我以从门口到吃饭过程来描述Netty服务器所需要的配置信息。
1、门店就是引导服务器(ServerBootstrap),没有门店,也不需要服务员和顾客。
2、门店需要服务员,海底捞的服务员分为门迎服务员(bossGroup)和桌台服务员(workerGroup),比如在这里我们配置了1个门迎和8个桌台,这个数字不是乱写的,首先门迎不需要很多,桌台服务员也和店里的桌子个数有关,对于服务器来讲,就是和CPU的核数有关,一般设置为CPU核数*2+1。
3、将服务员带到门店( bootstrap.group(bossGroup, workerGroup) //设置两个线程组)
4、门迎服务员可能什么都不懂,我们需要对他进行培训,让他知道如何和新来的顾客打交道(.channel(NioServerSocketChannel.class) //使用NioSocketChannel作为服务器的通道),以及配置他最多可去迎接多少个顾客(.option(ChannelOption.SO_BACKLOG, 128) //设置线程队列等待连接个数),以及要不要及多久和顾客打一次招呼( .childOption(ChannelOption.SO_KEEPALIVE, true) //设置保持活动连接状态)
5、门迎比较傻,他还不认识里面的桌台服务员,要把桌台服务员介绍给他。(.childHandler(new ChannelInitializer() {//设置workerGroup的eventLoop对应的管道处理器)
6、桌台的服务员也很傻,需要对他培训,教他怎么调油碗,教他怎么倒水,让顾客点菜,这里的单个操作就是(ChannelHandler,消息处理器),整个培训就叫做(ChannelPipeline)
socketChannel.pipeline().addLast(new NettyServerHandler());//这里只有一个,实际的应用场景会有很多。
7、门店不光需要去工商局注册,还需要实际的地址,也就需要绑定占用一个端口。我们可以一边培训服务员,一边装修门店,这就叫做异步方法,但是如果服务员培训好了,门店还没装修好,就必须进行同步,让服务员等门店装修好了才能上班。 ChannelFuture channelFuture = bootstrap.bind(6668).sync(); //绑定一个端口,并且同步,启动服务器
public class NettyServer {
public static void main(String[] args) throws InterruptedException {
//创建BossGroup和WorkerGroup
//说明:
//1. 创建两个线程组bossGroup和workerGroup
//2. bossGroup只是处理链接请求,真正的和客户端业务处理,会交给workerGroup
//3. 两个都是无限循环的
//4. bossGroup和workerGroup含有子线程的(NioEventLoop)的个数,默认实际cup核数*2
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup(8);
try {
/**
* 创建服务器端的启动对象,配置参数
*/
ServerBootstrap bootstrap = new ServerBootstrap();
/**
* 使用链式编程来进行设置
*/
bootstrap.group(bossGroup, workerGroup) //设置两个线程组
.channel(NioServerSocketChannel.class) //使用NioSocketChannel作为服务器的通道
.option(ChannelOption.SO_BACKLOG, 128) //设置线程队列等待连接个数
.childOption(ChannelOption.SO_KEEPALIVE, true) //设置保持活动连接状态
.childHandler(new ChannelInitializer<SocketChannel>() {//设置workerGroup的eventLoop对应的管道处理器
//给pipeline设置处理器
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//可以使用集合管理SocketChannel,在推送消息时,可以将业务加入到各个chanel对应的NIOEventLoop的taskQueue或ScheduleTaskQueue
log.info("客户端SocketChannel hashCode={}", socketChannel.hashCode());
socketChannel.pipeline().addLast(new NettyServerHandler());
}
});
log.info("服务器 is ready...");
//涉及netty异步模型
ChannelFuture channelFuture = bootstrap.bind(6668).sync(); //绑定一个端口,并且同步,启动服务器
//给channelFuture注册监听器,监控我们关系的事件
channelFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if(future.isSuccess()) {
log.info("监听端口6668成功");
}else {
log.info("监听端口失败");
}
}
});
log.info("判断是否是异步操作");
//对关闭通道进行监听
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
标签:Netty,服务员,new,workerGroup,bossGroup,核心,组件,服务器 来源: https://blog.csdn.net/qq_38173650/article/details/117293972