# 跟闪电侠学Netty:Netty即时聊天实战与底层原理
Netty是一个异步基于**事件驱动**的**高性能网络通信**框架,可以看做是对NIO和BIO的封装,并提供了简单易用的API、Handler和工具类等,
用以快速开发高性能、高可靠性的网络服务端和客户端程序。
### 1. 创建服务端
服务端启动需要创建 `ServerBootstrap` 对象,并完成**初始化线程模型**,**配置IO模型**和**添加业务处理逻辑(Handler)**。在添加业务处理逻辑时,
调用的是 `childHandler()` 方法添加了一个 `ChannelInitializer`,代码示例如下
```java
// 负责服务端的启动
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 以下两个对象可以看做是两个线程组
// boss线程组负责监听端口,接受新的连接
NioEventLoopGroup boss = new NioEventLoopGroup();
// worker线程组负责读取数据
NioEventLoopGroup worker = new NioEventLoopGroup();
// 配置线程组并指定NIO模型
serverBootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
// 定义后续每个 新连接 的读写业务逻辑
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline()
// 添加业务处理逻辑
.addLast(new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
System.out.println(msg);
}
});
}
});
// 绑定端口号
serverBootstrap.bind(2002);
```
通过调用 `.channel(NioServerSocketChannel.class)` 方法指定 `Channel` 类型为NIO类型,如果要指定为BIO类型,参数改成 `OioServerSocketChannel.class` 即可。
其中 `nioSocketChannel.pipeline()` 用来获取 `PipeLine` 对象,调用方法 `addLast()` 添加必要的业务处理逻辑,这里采用的是**责任链模式**,
会将每个Handler作为一个节点进行处理。
#### 1.1 创建客户端
客户端与服务端启动类似,不同的是,客户端需要创建 `Bootstrap` 对象来启动,并指定一个客户端线程组,
相同的是都需要完成**初始化线程模型**,**配置IO模型**和**添加业务处理逻辑(Handler)**, 代码示例如下
```java
// 负责客户端的启动
Bootstrap bootstrap = new Bootstrap();
// 客户端的线程模型
NioEventLoopGroup group = new NioEventLoopGroup();
// 指定线程组和NIO模型
bootstrap.group(group).channel(NioSocketChannel.class)
// handler() 方法封装业务处理逻辑
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline()
// 添加业务处理逻辑
.addLast(new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
System.out.println(msg);
}
});
}
});
// 连接服务端IP和端口
bootstrap.connect("127.0.0.1", 2002);
```
(注意:下文中内容均以服务端代码示例为准)
### 2. 编码和解码
客户端与服务端进行通信,通信的消息是以**二进制字节流**的形式通过 `Channel` 进行传递的,所以当我们在客户端封装好**Java业务对象**后,
需要将其按照协议转换成**字节数组**,并且当服务端接受到该**二进制字节流**时,需要将其根据协议再次解码成**Java业务对象**进行逻辑处理,
这就是**编码和解码**的过程。Netty 为我们提供了 `MessageToByteEncoder` 用于编码,`ByteToMessageDecoder` 用于解码。
#### 2.1 MessageToByteEncoder
用于将Java对象编码成字节数组并写入 `ByteBuf`,代码示例如下
```java
public class TcpEncoder extends MessageToByteEncoder<Message> {
/**
* 序列化器
*/
private final Serializer serializer;
public TcpEncoder(Serializer serializer) {
this.serializer = serializer;
}
/**
* 编码的执行逻辑
*
* @param message 需要被编码的消息对象
* @param byteBuf 将字节数组写入ByteBuf
*/
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Message message, ByteBuf byteBuf) throws Exception {
// 通过自定义的序列化器将对象转换成字节数组
byte[] bytes = serializer.serialize(message);
// 将字节数组写入 ByteBuf 便完成了对象的编码流程
byteBuf.writeBytes(bytes);
}
}
```
#### 2.2 ByteToMessageDecoder
它用于将接收到的二进制数据流解码成Java对象,与上述代码类似,只不过是将该过程反过来了而已,代码示例如下
```java
public class TcpDecoder extends ByteToMessageDecoder {
/**
* 序列化器
*/
private final Serializer serializer;
public TcpDecoder(Serializer serializer) {
this.serializer = serializer;
}
/**
* 解码的执行逻辑
*
* @param byteBuf 接收到的ByteBuf对象
* @param list 任何完成解码的Java对象添加到该List中即可
*/
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception {
// 根据协议自定义的解码逻辑将其解码成Java对象
Message message = serializer.deSerialize(byteBuf);
// 解码完成后添加到List中即可
list.add(message);
}
}
```
#### 2.3 注意要点
ByteBuf默认情况下使用的是**堆外内存**,不进行内存释放会发生内存溢出。不过 `ByteToMessageDecoder` 和 `MessageToByteEncoder` 这两个解码和编码
`Handler` 会自动帮我们完成内存释放的操作,无需再次手动释放。因为我们实现的 `encode()` 和 `decode()` 方法只是这两个 `Handler` 源码中执行的一个环节,
最终会在 finally 代码块中完成对内存的释放,具体内容可阅读 `MessageToByteEncoder` 中第99行 `write()` 方法源码。
#### 2.4 在服务端中添加编码解码Handler
```java
serverBootstrap.group(boss, worker).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline()
// 接收到请求时进行解码
.addLast(new TcpDecoder(serializer))
// 发送请求时进行编码
.addLast(new TcpEncoder(serializer));
}
});
```
### 3. 添加业务处理Handler
在Netty框架中,客户端与服务端的每个连接都对应着一个 `Channel`,而这个 `Channel` 的所有处理逻辑都封装在一个叫作 `ChannelPipeline` 的对象里。
`ChannelPipeline` 是一个双向链表,它使用的是**责任链模式**,每个链表节点都是一个 `Handler`,能通它能获取 `Channel` 相关的上下文信息(ChannelHandlerContext)。
Netty为我们提供了多种读取 `Channel` 中数据的 `Handler`,其中比较常用的是 `ChannelInboundHandlerAdapter` 和 `SimpleChannelInboundHandler`,
下文中我们以读取心跳消息为例。
#### 3.1 ChannelInboundHandlerAdapter
如下为处理心跳业务逻辑的 `Handler`,具体执行逻辑参考代码和注释即可
```java
public class HeartBeatHandler extends Ch
没有合适的资源?快使用搜索试试~ 我知道了~
跟闪电侠学Netty:Netty即时聊天实战与底层原理-book-netty.zip
共82个文件
java:75个
png:2个
xml:1个
1星 需积分: 0 41 下载量 64 浏览量
2023-11-07
20:44:28
上传
评论
收藏 885KB ZIP 举报
温馨提示
跟闪电侠学Netty:Netty即时聊天实战与底层原理-book-netty
资源推荐
资源详情
资源评论
收起资源包目录
跟闪电侠学Netty:Netty即时聊天实战与底层原理-book-netty.zip (82个子文件)
book-netty-master
pom.xml 1KB
src
test
java
SerializerTest.java 1KB
main
java
netty
book
handlerchildhandler
client
FirstClientHandler.java 1KB
NettyClient.java 961B
server
FirstServerHandler.java 1KB
NettyServer.java 2KB
inoutbound
out
OutboundHandlerA.java 472B
OutboundHandlerB.java 472B
in
InboundHandlerB.java 406B
InboundHandlerA.java 406B
practice
constant
Attributes.java 329B
protocol
command
Command.java 1KB
Packet.java 701B
response
QuitGroupResponsePacket.java 570B
CreateGroupResponsePacket.java 717B
JoinGroupResponsePacket.java 599B
HeartBeatResponsePacket.java 389B
GroupMessageResponsePacket.java 589B
ListGroupMembersResponsePacket.java 637B
MessageResponsePacket.java 805B
LoginResponsePacket.java 666B
request
CreateGroupRequestPacket.java 602B
JoinGroupRequestPacket.java 506B
GroupMessageRequestPacket.java 688B
MessageRequestPacket.java 666B
LoginRequestPacket.java 649B
QuitGroupRequestPacket.java 538B
HeartBeatRequestPacket.java 389B
ListGroupMembersRequestPacket.java 527B
handler
LifeCycleHandler.java 3KB
client
GroupMessageHandler.java 888B
ListGroupMembersHandler.java 876B
MessageHandler.java 962B
ClientHandler.java 2KB
LoginHandler.java 1KB
JoinGroupHandler.java 940B
CreateGroupHandler.java 876B
HeartBeatHandler.java 1KB
QuitGroupHandler.java 943B
MyIdleStateHandler.java 854B
server
GroupMessageHandler.java 2KB
ListGroupMembersHandler.java 2KB
MessageHandler.java 2KB
ServerHandler.java 2KB
LoginHandler.java 2KB
AuthHandler.java 1KB
JoinGroupHandler.java 1KB
CreateGroupHandler.java 2KB
HeartBeatHandler.java 806B
QuitGroupHandler.java 1KB
SplitHandler.java 875B
serialize
PacketCodeC.java 4KB
Serializer.java 455B
algorithm
SerializerAlgorithm.java 358B
codec
PacketEncoder.java 585B
PacketCodecHandler.java 1KB
PacketDecoder.java 553B
impl
JSONSerializer.java 606B
client
NettyClient.java 4KB
command
ConsoleCommand.java 389B
ConsoleCommandManger.java 2KB
impl
LoginConsoleCommand.java 2KB
JoinGroupConsoleCommand.java 748B
CreateGroupConsoleCommand.java 984B
ListGroupMembersConsoleCommand.java 800B
SendToUserConsoleCommand.java 1KB
QuitGroupConsoleCommand.java 758B
SendToGroupConsoleCommand.java 759B
server
NettyServer.java 3KB
util
SessionUtil.java 2KB
session
Session.java 378B
bio
IOClient.java 598B
IOServer.java 1KB
netty
NettyClient.java 3KB
NettyServer.java 4KB
bytebuf
ByteBufTest.java 3KB
LICENSE 11KB
.gitignore 278B
images
NioEventLoopGroup构造方法.jpg 127KB
标准协议.png 386KB
粘包日志.png 306KB
README.md 33KB
共 82 条
- 1
资源评论
- 爱喝纯牛奶的爷们2023-11-26不是书,没有任何意义的下载 #毫无价值
武昌库里写JAVA
- 粉丝: 3136
- 资源: 1872
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 论文(最终)_20240430235101.pdf
- 基于python编写的Keras深度学习框架开发,利用卷积神经网络CNN,快速识别图片并进行分类
- 最全空间计量实证方法(空间杜宾模型和检验以及结果解释文档).txt
- 5uonly.apk
- 蓝桥杯Python组的历年真题
- 2023-04-06-项目笔记 - 第一百十九阶段 - 4.4.2.117全局变量的作用域-117 -2024.04.30
- 2023-04-06-项目笔记 - 第一百十九阶段 - 4.4.2.117全局变量的作用域-117 -2024.04.30
- 前端开发技术实验报告:内含4四实验&实验报告
- Highlight Plus v20.0.1
- 林周瑜-论文.docx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功