整理 Netty WebSocket
文前说明
作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。
本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。
-
Netty是针对Java Nio(非阻塞式)Java网络API,隐藏背后复杂性(可靠、可扩展的事件处理器处理和调度数据,并尽可能的保证有效、正确性和安全性),提供易于使用的服务器\客户端网络编程框架。
-
Channel是Nio的基本结构,是作为数据传入和传出的运输工具。
-
Callback是一个回调简单方法,Netty内部使用回调处理事件。
例如:
public class ChannelHandlerAdapter implements ChannelHandler
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
ctx.fireChannelActive();
}
一旦一个新的连接建立,则调用channelActive方法。
- 除了回调方式,还可以使用Future,提供另外一种通知应用操作方式。Netty提供了ChannelFuture,执行异步操作。
例如:
ChannelFuture future = channel.connect(new InetSocketAddress("192.168.96.103", 25));
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
ByteBuf buffer = Unpooled.copiedBuffer("连接成功!", Charset.defaultCharset());
ChannelFuture wf = future.channel().writeAndFlush(buffer);
} else {
Throwable cause = future.cause(); cause.printStackTrace();
}
}
})
-
远程连接返回future,如果返回成功,则写入channel。
-
如果失败,可以从 ChannelFuture中获取Throwable。
-
这是一个异步,无需等待的过程。operationComplete是操作方法。
-
Netty使用不同的事件更改或操作状态,每一个事件都可以定义一个事件处理器,ChannelHandler将各种程序处理器进行了抽象,实际就是响应对应事件的回调。
-
ChannelFuture使用事件和future本身,创建具有Netty特性的消费者。
-
每个Channel都有关联的ChannelPipeline,代表ChannelHandler实例的链,如果一个Netty Handler不处理exceptionCaught,将传递给下一个ChannelHandler实例,因此至少需要有一个覆盖了exceptionCaught的ChannelHandler。
-
引导服务器/客户端Socket的过程如下:
-
创建EventLoopGroup(定义NioEventLoopGroup,使用NIO方式),创建一个(客户端:创建两个)。
-
创建ServerBootstrap。(客户端:创建Bootstrap)
-
指定Socket端口。(客户端:指定IP地址和端口)
-
NIO(非阻塞),高连接数时使用。
-
OIO(阻塞),低连接数,需要低延迟,阻塞时使用。
-
Local(同一个JVM虚拟机的本地(服务器和客户端)通信),同一个JVM内通信使用。
-
Embedded(在没有真正网络的传输中使用ChannelHandler,内嵌式)四种。测试ChannelHandler时使用。
-
-
指定ChannelInitializer。childHandler(new ChannelInitializer())。
-
指定Handler处理器到Channel的ChannelPipeline中。
-
绑定服务器,sync等待服务器关闭。.bind(1234).sync()(客户端:连接服务器.connect().sync())
-
关闭Channel。closeFuture().sync()
-
关闭EventLoopGroup,释放资源。shutDownGraceFully()。
Bootstrap
引导类,应用程序网络层配置的容器。
Channel
一个Socket连接,封装IO基本操作。
ChannelHandler
支持很多协议,提供数据处理的容器。
ChannelPipeline
提供Handler链的容器。
EventLoop
用于处理Channel的I/O操作,一个EventLoop处理多个Channel,一个EventLoopGroup包含多个EventLoop。
ChannelFuture
Netty的所有I/O操作都是异步的,无法立即返回操作结构,可以通过ChannelFuture注册事件,当操作完成时,获取事件通知。
-
服务器ServerBootstrap,需要两个EventLoopGroup,一个是单例的,负责监测本地端口,并且轮询客户端是否建立连接(创建Channel),一个负责接收处理Channel的消息(分配一个EventLoop给Channel)。
-
ChannelHandler分为入站(ChannelInHandler)和出站(ChannelOutHandler)两种,在引导程序的时候,被加入ChannelPipeline,被增加进入的顺序,决定了执行的顺序。
入站时,从ChannelPipeline的第一个ChannelInHandler执行到最后一个。出站时,从ChannelPipeline的最后一个ChannelOutHandler执行到第一个。在ChannelHandler之间传递的是ChannelHandlerContext,可以看作是ChannelHandler与ChannelPipeline之间的绑定关系。通过ChannelHandlerContext.channel().writeAndFlush写入消息,是到达ChannelPipeline尾部才写入消息,而ChannelHandlerContext.writeAndFlush写入消息,是到达下一个ChannelInHandler就写入消息。
SimpleChannelboundHandler
常见处理器,只需要继承SimpleChannelboundHandler即可。
选择器参数
方法名称 | 描述 |
---|---|
OP_ACCEPT | 有新连接时通知 |
OP_CONNECT | 连接完成后通知 |
OP_READ | 准备好读取数据时通知 |
OP_WRITE | 准备好写入数据时通知 |
Channel的生命周期
状态 | 描述 |
---|---|
channelActive | channel变为激活状态,连接到远程主机,可以收发消息。 |
channelInactive | channel处于非激活状态,没有连接到远程主机 |
channelRegistered | channel注册到一个EventLoop。 |
channelUnregistered | channel已经创建,但是未注册到一个EventLoop。 |
messageReceived | 接收消息时调用。 |
Handler的生命周期
状态 | 描述 |
---|---|
handlerAdded | 当ChannelHandler增加到ChannelPipeline。 |
handlerRemoved | 当ChannelHandler移除ChannelPipeline。 |
exceptionCaught | 当ChannelPipeline抛出异常时调用。 |
-
ChannelPipeline可以动态的添加和删除Handler。可以通过ChannelHandlerContext获得关联的pipeline,从而实现一些动态加载Handler效果。
-
ChannelHandler可以属于多个ChannelPipeline,但是必须添加@Sharable注解,表示可以共享使用,否则会抛出异常。并且要保证ChannelHandler是线程安全的。这种效果一般是为了实现共享ChannelHandler以此来实现跨多个渠道收集统计数据。
实现SSL/TLS加密解密的SslHandler
大多数情况下,SslHandler都作为ChannelPipeline的第一个Handler。
实现HTTP消息聚合
增加HTTP消息编码器,HttpServerCodec,消息聚合HttpObjectAggregator(512)。最大值为512kb。
实现HTTPS
只需增加SslHandler。
实现WebSocket
-
可以通过HTTPS实现WebSocket握手。
-
数据传输可以通过
名称 | 描述 |
---|---|
BinaryWebSocketFrame | 二进制数据。 |
TextWebSocketFrame | 文本数据。 |
ContinuationWebSocketFrame | 超大文本或者二进制数据。 |
空闲连接以及超时
-
IdleStateHandler:如果连接闲置时间过长,则触发IdleStateEvent事件。
-
ReadTimeoutHandler:在指定时间间隔没有接收到入站数据则抛出ReadTimeoutExcepiton异常并关闭Channel。
-
WriteTimeoutHandler抛出WriteTimeoutExcepiton异常并关闭Channel,异常都可以通过exceptionCaught捕获。
ChunkedWriteHandler
处理大数据传输,支持异步写大数据流,不引起高内存消耗。
引导客户端和无连接协议
名称 | 描述 |
---|---|
group | 设置EventLoopGroup处理所有的Channel的事件。 |
channel | 定义Channel处理方式,默认支持4种定义,NIO、OIO、Local和Embedded |
option | 应用于新创建的Channel,作用于ChannelConfig,创建连接后无效果。 |
attr | 设置属性,创建连接后无效果。 |
handler | 添加Handler到ChannelPipeline,初始化连接时执行。 |
clone | 拷贝Bootstrap属性。 |
connect | 连接到远端,参数IP(域名)和端口号,返回一个ChannelFuture。 |
EventLoopGroup与Channel需要保持一致的兼容性,否则会抛出IIIegalStateException异常。
引导服务器
名称 | 描述 |
---|---|
group | 设置两个,一个EventLoopGroup处理监听端口,一个EventLoopGroup处理所有的Channel的事件。 |
channel | 定义Channel处理方式,默认支持4种定义,NIO、OIO、Local和Embedded |
option | 应用于新创建的Channel,作用于ChannelConfig,创建连接后无效果。 |
childOption | 应用于已接收的Channel,作用于ChannelConfig。 |
attr | 设置属性,创建连接后无效果。 |
childAttr | 设置属性,作用于已接收的Channel。 |
handler | 添加Handler到ChannelPipeline,初始化连接时执行。 |
ChildHandler | 添加Handler到ChannelPipeline,建立连接后执行。 |
clone | 拷贝Bootstrap属性。 |
bind | 绑定本地端口,参数端口号,返回一个ChannelFuture。 |
可以通过group.shutdownGracefully()实现优雅的关闭。
WebSocketServerProtocolHandler
处理除TextWebSocketFrame以外的其他类型帧。
WebSocket的初始化流程
名称 | 职责 |
---|---|
HttpServerCodec | Http编码器。 |
HttpObjectAggregator | Http消息聚合。 |
ChunkedWriteHandler | 大数据处理,主要针对SSL加密解密。 |
HttpRequestHandler | 用户自定义处理ws请求。 |
WebSocketServerProtocolHandler | 处理除TextWebSocketFrame以外的消息事件。所有规定的WebSocket帧类型。 |
TextWebSocketFrameHandler | 用户自定义处理TextWebSocketFrame的消息事件。 |
在ChannelPipeline执行的过程中,会替换或者删除Handler,当WebSocket执行完成后剩余WebSocketFrameDecoder、WebSocketFrameEncoder、WebSocketServerProtocolHandler和TextWebSocketFrameHandler四个Handler。