1.Netty是什么
Netty is an asynchronous event-driven network application framework
for rapid development of maintainable high performance protocol servers & clients.
Netty是一个异步、事件驱动的网络应用框架
用于快速开发可维护的高性能协议服务器和客户端。
注意:Netty的异步并非是用AIO实现的。
Netty的异步机制是通过Java NIO 来实现的。NIO是一种基于缓冲区、非阻塞、事件驱动的I/O模型,它提供了一套新的I/O API,包括了Channel、Selector、Buffer等核心组件,可以实现高效、可靠的异步I/O操作。Netty在其基础上进行了封装和优化,提供了更加易用、高效的异步I/O框架。在Netty中,当进行I/O操作时,可以通过Channel和Selector来实现异步执行,而回调机制则是实现异步执行的重要手段。
2.快速开始
所需依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.86.Final</version>
</dependency>服务端
HelloServerHelloServerimport io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
public class HelloServer {
public static void main(String[] args) {
// 1. ServerBootstrap:启动器,负责组装netty组件,启动服务器
new ServerBootstrap()
// 2. BossEventLoop(负责连接) , WorkerEventLoop(负责读写) (selector, thread)
.group(new NioEventLoopGroup())
// 3.选择服务器的ServerSocketChannel实现
.channel(NioServerSocketChannel.class)
// 4. worker(child) , 决定了worker能执行什么操作(handler)
.childHandler(
// 5. channel 代表和客户端进行读写的通道 Initializer:初始化器,负责添加别的handler
new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// 6. 添加具体handler
ch.pipeline().addLast(new StringDecoder()); //将 ByteBuf 转为字符串
ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){ //自定义handler
@Override //读事件
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(msg);
}
});
}
})
.bind(8080);
}
}客户端
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import java.net.InetSocketAddress;
public class HelloClient {
public static void main(String[] args) throws InterruptedException {
// 1.启动类
new Bootstrap()
// 2.添加EventLoop
.group(new NioEventLoopGroup())
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder());
}
})
.connect(new InetSocketAddress("localhost",8080))
.sync()
.channel()
//发送数据
.writeAndFlush("hello world");
}
}3.对HelloServer中组件的解释
ServerBootstrap()
ServerBootstrap是Netty中用于创建服务器端的启动类,它提供了一组用于配置、启动和关闭服务器的API,是Netty服务器端应用程序的入口点。
在使用ServerBootstrap时,开发者需要配置一些参数,例如服务器监听的端口号、通道类型、事件处理器等。在启动服务器后,ServerBootstrap会自动创建一个I/O线程池和一个事件循环组,用于处理客户端连接、请求和响应等I/O操作。
ServerBootstrap的主要方法包括:
- group(EventLoopGroup bossGroup, EventLoopGroup workerGroup):用于设置服务端的主从事件循环组。
- channel(Class<? extends ServerChannel> channelClass):用于设置服务端的通道类型。
- childHandler(ChannelInitializer<Channel> childHandler):用于设置连接到服务器的客户端的处理器,用于处理客户端的请求和响应。
- bind(int port):用于绑定服务器端口并启动服务器。
通过ServerBootstrap的API,开发者可以轻松创建一个高性能、可扩展的服务器端应用程序,并且可以方便地配置、启动和关闭服务器。
NioEventLoopGroup()
NioEventLoopGroup是Netty中用于处理I/O事件的线程组,它是基于Java NIO实现的多线程事件循环器。
在Netty中,所有的I/O操作都是在NioEventLoopGroup中的事件循环器中进行的,NioEventLoopGroup会自动创建多个NioEventLoop线程,每个NioEventLoop线程负责处理一组Channel的I/O事件。
NioEventLoopGroup的主要作用是管理NioEventLoop线程的创建、启动和关闭,并且将I/O事件分发到各个NioEventLoop线程中进行处理。在Netty中,通常会创建两个NioEventLoopGroup,一个用于处理连接请求的bossGroup,一个用于处理客户端的I/O请求的workerGroup。
当有新的连接请求时,bossGroup会将连接请求分配给workerGroup中的某个NioEventLoop线程进行处理;当有I/O事件发生时,NioEventLoop线程会将事件分发给对应的ChannelHandler进行处理,并且可以将处理结果返回给客户端。
总之,NioEventLoopGroup是Netty中用于处理I/O事件的线程组,它可以提高程序的并发性能和响应速度。
NioServerSocketChannel
NioServerSocketChannel是Netty中用于表示服务器端监听的通道类型,它继承自AbstractNioChannel类,是基于Java NIO实现的ServerSocketChannel的封装。
在Netty中,NioServerSocketChannel用于监听客户端的连接请求,并将连接请求分配给对应的NioSocketChannel进行处理。当有新的连接请求到达时,NioServerSocketChannel会将请求封装成NioSocketChannel对象,并将其注册到EventLoop中,等待I/O事件的发生。
NioServerSocketChannel的主要属性和方法包括:
- pipeline():用于获取当前通道的ChannelPipeline对象,可以向其中添加或删除ChannelHandler。
- bind(InetSocketAddress localAddress):用于将当前通道绑定到指定的本地地址。
- eventLoop():用于获取当前通道所在的EventLoop对象。
- channelRead(Object msg):用于处理客户端连接请求,将连接请求封装成NioSocketChannel对象,并将其注册到EventLoop中。
总之,NioServerSocketChannel是Netty中用于表示服务器端监听的通道类型,通过它可以高效地监听客户端的连接请求,并将请求分配给对应的NioSocketChannel进行处理。
ChannelInitializer
ChannelInitializer是Netty中用于初始化Channel的抽象类,它提供了一些方法用于初始化新创建的Channel的ChannelPipeline。
在Netty中,每个Channel都有一个ChannelPipeline,用于处理该Channel的所有事件。ChannelInitializer是一个特殊的ChannelHandler,它可以向ChannelPipeline中添加其他的ChannelHandler,并完成一些初始化工作。
ChannelInitializer的主要方法是initChannel(),它会在Channel被创建时被调用,并且会将新创建的Channel作为参数传递进来。开发者可以在该方法中向ChannelPipeline中添加一些自定义的ChannelHandler,例如解码器、编码器、业务逻辑处理器等。
public class MyChannelInitializer extends ChannelInitializer<NioSocketChannel> {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new MyDecoder());
pipeline.addLast("encoder", new MyEncoder());
pipeline.addLast("handler", new MyHandler());
}
}在上述代码中,MyChannelInitializer继承自ChannelInitializer<NioSocketChannel>,并且实现了initChannel()方法,该方法将自定义的MyDecoder、MyEncoder和MyHandler添加到了NioSocketChannel的ChannelPipeline中,完成了NioSocketChannel的初始化工作。
为什么服务器端是new ChannelInitializer<NioSocketChannel>,而不是NioServerSocketChannel ?
在服务器端,使用的是NioServerSocketChannel来表示服务器端监听的通道类型,而不是在ChannelInitializer中指定NioServerSocketChannel类型。
NioServerSocketChannel是用于监听客户端连接请求的通道类型,当有新的连接请求到达时,NioServerSocketChannel会将请求封装成NioSocketChannel对象,并将其注册到EventLoop中进行处理。因此,在服务器端,需要使用NioServerSocketChannel来监听客户端连接请求。
而在ChannelInitializer中,需要指定要对哪种类型的Channel进行初始化。在服务器端,需要对客户端连接请求分配的NioSocketChannel进行初始化,因此需要将ChannelInitializer的泛型类型设置为NioSocketChannel。
ChannelInboundHandlerAdapter
ChannelInboundHandlerAdapter是Netty中实现了ChannelInboundHandler接口的适配器类,它提供了一些默认的实现,使得开发者可以只实现需要的方法,而不必实现接口中的所有方法。
在Netty中,所有的ChannelHandler都必须实现ChannelHandler接口,其中包括ChannelInboundHandler和ChannelOutboundHandler接口。ChannelInboundHandler用于处理入站数据,而ChannelOutboundHandler用于处理出站数据。
ChannelInboundHandlerAdapter是ChannelInboundHandler接口的适配器类,它提供了一些默认的实现,例如channelRead()、channelActive()、channelInactive()等方法。开发者可以继承ChannelInboundHandlerAdapter类,并重写需要的方法,从而实现自己的业务逻辑。
public class MyHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 处理接收到的数据
String data = (String) msg;
// 打印接收到的数据
System.out.println("Receive data from client: " + data);
// 将处理结果返回给客户端
String response = "Received your message: " + data;
ctx.writeAndFlush(response);
}
}在上述代码中,MyHandler继承自ChannelInboundHandlerAdapter,重写了channelRead()方法,该方法用于处理接收到的消息。在方法中,将接收到的消息转换成String类型,并且打印出来,然后将处理结果返回给客户端。
















