1.引入Netty依赖
java
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.39.Final</version>
</dependency>
2.服务端
java
public class HelloServer {
public static void main(String[] args) {
// 1.启动器,负责组装Netty组件,启动服务器
new ServerBootstrap()
// 2.BossEventLoop,WorkerEventLoop(selector,thread),group组
.group(new NioEventLoopGroup())
// 3.选择服务器的ServerSocketChannel 实现
.channel(NioServerSocketChannel.class) // NIO,BIO,OIO
// 4.Boss负责处理连接,worker(child)负责处理读写,决定了worker(child)能执行哪些操作handler
.childHandler(
// 5. channel代表和客户端进行数据读写的通道 Initializer初始化,负责添加别的handler
new ChannelInitializer<NioSocketChannel>() {
@Override // 连接建立后被调用
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
// 6. 添加具体的handler
nioSocketChannel.pipeline().addLast(new StringDecoder()); //将ByteBuf 转换为字符串
nioSocketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter(){ // 自定义handler
// 读事件
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//打印上一个handler已经处理好的字符串
System.out.println(msg);
}
});
}
})
// 7. 绑定监听端口
.bind(8888);
}
}
第二步中NioEventLoopGroup,会有一个线程不断循环,配合选择器selector,监测accept、read等事件。
当accept事件发生以后,也就是连接建立以后,由某个一EventLoop对象处理,才会去执行第六步中的initChannel方法。
3.客户端
java
public class HelloClient {
public static void main(String[] args) throws InterruptedException {
// 1.启动器,负责组件netty组件,启动客户端
new Bootstrap()
// 2. 添加 EventLoop(BossEventLoop,WorkerEventLoop(selector, thread)),group组
.group(new NioEventLoopGroup())
// 3. 选择客户端的SocketChannel实现
.channel(NioSocketChannel.class)
// 4. 添加处理器
.handler(
// 5. channel代表和客户端进行数据读写的通道 Initializer初始化,负责添加别的handler
new ChannelInitializer<NioSocketChannel>() {
@Override // 连接建立后被调用
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast(new StringEncoder()); //将String-> ByteBuf
}
}
)
// 6.连接到服务端
.connect(new InetSocketAddress("localhost", 8888))
.sync()
.channel()
// 7.向服务端发送数据
.writeAndFlush("hello netty");
}
}
sync方法是阻塞方法,客户端与服务端连接建立成功才会继续执行。然后服务端的NioEventLoopGroup中的某一个EventLoop就会处理accept事件。
客户端发送了数据writeAndFlush方法后,就会去执行pipeline上的具体的每个handler中的方法,比如会执行StringEncoder Handler,也就是出栈,将String转成ByteBuf对象。
然后服务端的 NioEventLoopGroup中的某一个EventLoop就会处理read事件。
服务端接收到数据,会执行StringDecoder Handler,也就是入栈,将ByteBuf对象转成String对象。再传递给下一个handler,直接将消息打印到控制台。
channel理解为数据通道。
msg理解为流动的数据,最开始输入ByteBuf,经过pipeline加工,会变成其他类型的对象,最后输出有变成ByteBuf对象。
handler理解为数据的处理工序,工序有多道,合在一起就是pipeline,传播给每个handler,handler对自己感兴趣的事件进行处理。handler分为InBound入栈和OutBound出栈两类。
eventLoop 理解为处理数据的工人,就是selector和Thread,工人可以管理多个channel的io操作,并且工人一旦负责了某个channel,就要负责到底(绑定)。工人按照pipeline顺序,依次按照handler的代码处理数据(入栈、出栈)。eventLoop就是一个单线程的线程池。