基于netty建立webSocket连接
为了使客户端服务器能够实现互相发送数据,不用等待对方响应(如HTTP请求,是单向的),所以需要实现基于 Netty 框架实现的 WebSocket 服务器,主要功能包括:
- 建立 WebSocket 连接并验证客户端身份(通过 Token)
- 处理客户端发送的文本消息
- 检测连接存活状态(心跳机制)
- 管理连接的生命周期(建立、断开等)
基本目录:
其中,
initrun:
在 SpringBoot 应用启动完成后(所有 Bean 加载就绪后),自动执行 run
方法,启动一个新线程,不阻塞主线程,执行nettyWebSocketStarter里的run方法,从而启动 Netty WebSocket 服务。
然后看nettyWebSocketStarter:
包括run方法和close方法。
线程池EventLoopGroup里有两个核心线程组bossGroup,workerGroup。
线程池:包含多个
EventLoop
(事件循环)。每个EventLoop
对应一个线程,负责处理一组通道(Channel
)的生命周期内的所有事件(如连接建立、数据读写、连接关闭等)。
bossGroup:
负责 接收客户端的连接请求,并将建立好的连接传递给 workerGroup
处理。
workerGroup:
负责 处理已建立连接的 IO 操作(如读取客户端发送的数据、向客户端写入数据等)
ok,再细看run和close:
可以看到,这里两次关闭两个线程组,
其中finally中:当真的执行了run方法后,无论成功与否,最后关闭group
而close:可能run方法根本没有执行起来,最后spring运行结束,创建的group就得即使清理,
两次关闭并不是冗余操作。
细看run方法:
ServerBootstrap:在netty中启动和配置服务器端 Channel(通道) 的核心辅助类。
1:绑定两个线程组
2:指定通道为netty的NioServerSocketChannel
3:配置服务器的处理器和客户端连接的各个处理器
4:绑定端口,启动服务
其中两个处理器:
用于处理连接周期,一般联合使用,
其中心跳处理器HandlerHeartBeat:
用来检测连接是否存活。
然后是token校验处理器handlerTokenValidation
首先:
@ChannelHandler.Sharable允许被多个channel共享,可以和多个ChannelPipeline关联。
默认情况下,一个Handler只能加入到一个ChannelPipeline中。
拦截token:
这里为什么提取出来的token要用集合来装:
HTTP请求允许同一参数名对应多个值,如:
ws://localhost:8080/ws?token=abc&token=def
虽然在当前业务中,token通常是唯一的(一个客户端连接对应一个 token
),但代码通过 List<String> tokens = queryDecoder.parameters().get("token")
接收参数,是为了兼容 HTTP 协议的这种特性,避免因参数格式异常(如意外出现多个 token
)导致的解析错误。
一般我们就拿集合的第一个作为真正token。
然后校验token和dto的正确对应关系。
如果token直接是没有,则构建HTTPResponse
校验成功后,传递给下一个处理器Handler,并且添加retain防止传的是一个空对象。
然后处理客户端消息的handlerWebSocket:
最后通过了处理器链,则netty启动成功,
.sync():阻塞当前线程(即执行run方法的线程),直到端口绑定操作完成(成功或失败)。
- 如果绑定成功,
sync()
会返回完成的ChannelFuture
,后续可通过channel()
获取服务器通道(Channel
)。 - 如果绑定失败(如端口被占用),会抛出异常,被后续的
catch
块捕获。
.channel():从完成的 ChannelFuture
中获取服务器通道实例(NioServerSocketChannel
)
channel.closeFuture().sync(): 再次阻塞当前线程(run()
方法的线程),直到服务器通道关闭。如果不阻塞,那么直接执行到finally关闭group。
第一次阻塞:确保服务器成功绑定端口后再继续执行。
第二次阻塞:让服务器主线程(run()
方法所在线程)进入等待状态,直到服务被关闭。
举个例子:
餐馆有个专门负责各种开关,关门等操作的人,它就负责餐馆的正常运作,防止餐馆突然关门,突然停电等意外,导致厨师做不了饭菜。
这个人就是负责阻塞,厨师就是服务器通道,差不多就这意思。
最后来看客户端服务器是否正常连接:
通过ws成功连接并发送消息:
感谢阅读>W<