目录
- 一、加入依赖
- 二、服务器端
- 三、客户端
- 四、服务端和客户端流程梳理
- 五、channel 、msg 、handler 和eventLoop 概念理解
- 5.1、channel 的理解
- 5.2、msg 的理解
- 5.3、handler 的理解
- 5.4、eventLoop 的理解
一、加入依赖
二、服务器端
2.1、服务器端代码
-
服务器端代码
package com.example.nettytest.netty.day1;
import 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;
import io.netty.handler.logging.LoggingHandler;
public class Server {
public static void main(String[] args) {
new ServerBootstrap()
.group(new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(
new ChannelInitializer<NioSocketChannel>() {
&#64;Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast(new LoggingHandler());
nioSocketChannel.pipeline().addLast(new StringDecoder());
nioSocketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter(){
&#64;Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("msg&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;"&#43;msg);
}
});
}
})
.bind(8080);
}
}
2.2、服务器端代码解读
-
代码1位置 &#xff1a;服务端启动器&#xff1a;负责组装netty组件
-
代码2位置 &#xff1a;创建 NioEventLoopGroup&#xff0c;可以简单理解为 线程池 &#43; Selector 后面会详细展开&#xff1b;
-
代码3位置&#xff1a;选择服务 Scoket 实现类&#xff0c;其中 NioServerSocketChannel 表示基于 NIO 的服务器端实现&#xff0c;其它实现还有
-
代码4位置&#xff1a;为啥方法叫 childHandler&#xff0c;是接下来添加的处理器都是给 SocketChannel 用的&#xff0c;而不是给 ServerSocketChannel。ChannelInitializer 处理器&#xff08;仅执行一次&#xff09;&#xff0c;它的作用是待客户端 SocketChannel 建立连接后&#xff0c;执行 initChannel 以便添加更多的处理器&#xff1b;
-
代码5位置&#xff1a;channel代表和客户端进行数据读写的通道 Initializer 初始化&#xff0c;负责添加别的 handler&#xff1b;
-
代码6位置&#xff1a;添加具体 handler&#xff1b;
-
代码7位置&#xff1a; ServerSocketChannel 绑定的监听端口&#xff1b;
三、客户端
3.1、客户端代码
package com.example.nettytest.netty.day1;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.net.InetSocketAddress;
public class Client {
public static void main(String[] args) throws InterruptedException {
new Bootstrap()
.group(new NioEventLoopGroup())
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
&#64;Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast(new StringEncoder());
}
})
.connect(new InetSocketAddress("localhost",8080))
.sync()
.channel()
.writeAndFlush("hello world &#xff01;");
}
}
3.2、客户端代码解读
- 代码1位置 &#xff1a;客户端启动器&#xff1b;
- 代码2位置 &#xff1a;创建 NioEventLoopGroup&#xff08;事件循环&#xff09;&#xff0c;同 Server服务端&#xff1b;
- 代码3位置 &#xff1a;选择客户 Socket 实现类&#xff0c;NioSocketChannel 表示基于 NIO 的客户端实现&#xff0c;其它实现还有
- 代码4位置 &#xff1a;添加 SocketChannel 的处理器&#xff0c;ChannelInitializer 处理器&#xff08;仅执行一次&#xff09;&#xff0c;它的作用是待客户端 SocketChannel 建立连接后&#xff0c;执行 initChannel 以便添加更多的处理器&#xff1b;
- 代码5位置 &#xff1a;指定要连接的服务器和端口&#xff1b;
- 代码6位置 &#xff1a;Netty 中很多方法都是异步的&#xff0c;如 connect&#xff0c;这时需要使用 sync 方法等待 connect 建立连接完毕&#xff1b;
- 代码7位置 &#xff1a;获取 channel 对象&#xff0c;它即为通道抽象&#xff0c;可以进行数据读写操作&#xff1b;
- 代码8位置 &#xff1a;入消息并清空缓冲区&#xff1b;
- 代码9位置 &#xff1a;消息会经过通道 handler 处理&#xff0c;这里是将 String &#61;> ByteBuf 发出&#xff1b;
数据经过网络传输&#xff0c;到达服务器端&#xff0c;服务器端 5 和 6 处的 handler 先后被触发&#xff0c;走完一个流程
四、服务端和客户端流程梳理
-
流程梳理
五、channel 、msg 、handler 和eventLoop 概念理解
5.1、channel 的理解
5.2、msg 的理解
- 把 msg 理解为流动的数据&#xff0c;最开始输入是 ByteBuf&#xff0c;但经过 pipeline 的加工&#xff0c;会变成其它类型对象&#xff0c;最后输出又变成 ByteBuf
5.3、handler 的理解
- 把 handler 理解为数据的处理工序
&#xff08;1&#xff09;、工序有多道&#xff0c;合在一起就是 pipeline&#xff0c;pipeline 负责发布事件&#xff08;读、读取完成…&#xff09;传播给每个 handler&#xff0c; handler 对自己感兴趣的事件进行处理&#xff08;重写了相应事件处理方法&#xff09;&#xff1b;
&#xff08;2&#xff09;、handler 分 Inbound 和 Outbound 两类&#xff1b;
5.4、eventLoop 的理解
- 把 eventLoop 理解为处理数据的工人
&#xff08;1&#xff09;、工人可以管理多个 channel 的 io 操作&#xff0c;并且一旦工人负责了某个 channel&#xff0c;就要负责到底&#xff08;绑定&#xff09;&#xff1b;
&#xff08;2&#xff09;、工人既可以执行 io 操作&#xff0c;也可以进行任务处理&#xff0c;每位工人有任务队列&#xff0c;队列里可以堆放多个 channel 的待处理任务&#xff0c;任务分为普通任务、定时任务&#xff1b;
&#xff08;3&#xff09;、工人按照 pipeline 顺序&#xff0c;依次按照 handler 的规划&#xff08;代码&#xff09;处理数据&#xff0c;可以为每道工序指定不同的工人&#xff1b;