网站首页 > 技术文章 正文
1. 前言
上一节,我们主要讲解了 Http 协议,本节我们来讲解 Netty 支持的另外一个 WebSocket 协议,WebSocket 是 HTML5 开始支持的全双工协议。
在真实的开发当中,其实 WebSocket 使用非常的广泛,特别是在目前前端技术越来越完善的情况下,很多应用都是基于前端技术去实现,比如:APP、小程序等主流应用,前端的技术完全可以开发出类似原生技术一样的产品,并且开发效率上比原生更加的快、用户体验更好。
这些应用涉及通信、聊天、推送等业务,则可以使用 WebSocket 来实现,因此,WebSocket 已经是目前非常主流的浏览器和服务端建立长连接的通信技术。
WebSocket 协议架构图如下所示:
2. 学习目的
Netty 虽然可以开发客户端和服务端的应用,但是 Netty 和 WebSocket 结合则是另外一个不同的应用方向。
应用方向一: 纯后端的应用,比如:框架、中间件通信等,则完全可以使用 Netty 来开发客户端和服务端,并且双方通过 TCP 协议来进行通信。
应用方向二: 前端(浏览器)和服务端之间通信,并且想实现类似长连接的效果,那么 WebSocket 和 Netty 则是主流,并且这部分的应用场景非常的广泛和运用非常的多。
因此,我们在学习完本章内容之后,我们就可以掌握这类的需求的开发(比如:聊天、消息推送),自己可以尝试去开发一款小程序在线聊天系统。
当真实的开发当中,也许很多人直接使用 Spring 封装的 WebSocket 或者其它第三方的框架(比如:netty-socketio)去实现。本节我们主要讲解原生 Netty 来开发 WebSocket 协议格式的数据请求,毕竟会用和知道知其所以然还是有区别的。
3. WebSocket 的 API
创建 WebSocket 对象,第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
var Socket = new WebSocket(url, [protocol] );
WebSocket 事件
事件 | 事件处理程序 | 描述 |
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
4. 环境搭建
本节,我们主要开发一个 Demo,主要功能如下:
- 前端页面(html)启动的时候,连接 WebSocket 服务端;
- 服务端往前端每隔 5s 推送一条消息。
环境搭建步骤:
- 创建一个 Maven 项目;
- 导入 Netty 坐标。
实例:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
5. 代码实现
5.1. Netty 主启动类
public class MyWebSocketServer {
public static void main(String[] args) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//因为基于http协议,使用http的编码和解码器
pipeline.addLast(new HttpServerCodec());
//是以块方式写,添加ChunkedWriteHandler处理器
pipeline.addLast(new ChunkedWriteHandler());
//http数据在传输过程中是分段, HttpObjectAggregator ,就是可以将多个段聚合
pipeline.addLast(new HttpObjectAggregator(8192));
//将 http协议升级为 ws协议 , 保持长连接
pipeline.addLast(new WebSocketServerProtocolHandler("/hello2"));
//自定义的handler ,处理业务逻辑
pipeline.addLast(new MyWebSocketHandler());
}
});
//启动服务器
ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
channelFuture.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
代码说明:
- WebSocket 比 TCP 和 Http 协议都稍微复杂一点,它其实是 TCP 和 Http 协议的结合,首先是连接之前发送的是 Http 协议请求,但是新增 Http 所没有的附加头信息 Upgrade: WebSocket 表明是一个申请协议升级的 Http 请求。其次,真正建立连接之后,其实底层是 TCP 协议长连接;
- HttpServerCodec 将请求和应答消息解码为 HTTP 消息;
- ChunkedWriteHandler 向客户端发送 HTML5 文件;
- http 数据在传输过程中是分段,当浏览器发送大量数据时,就会发出多次 http 请求, HttpObjectAggregator 可以将 HTTP 消息的多个部分合成一条完整的 HTTP 消息;
- WebSocketServerProtocolHandler 定义了 WebSocket 的对外暴露地址。
5.2 WebSocket 业务类
public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{
private SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//1.获取Channel通道
final Channel channel=ctx.channel();
//2.创建一个定时线程池
ScheduledExecutorService ses=Executors.newScheduledThreadPool(1);
//3.一秒钟之后只需,并且每隔5秒往浏览器发送数据
ses.scheduleWithFixedDelay(new Runnable() {
public void run() {
String sendTime=format.format(new Date());
channel.writeAndFlush(new TextWebSocketFrame("推送时间=" + sendTime));
}
},1,5, TimeUnit.SECONDS);
}
//接受浏览器消息
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
System.out.println("收到消息 " + msg.text());
}
//当web客户端连接后,触发方法
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
}
//当web客户端断开后,触发方法
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
}
}
代码说明:
其实 WebSocket 对于的 Handler 跟我们普通业务的 Handler 没有什么区别,这里主要使用定时线程池定时往浏览器推送消息,这个是传统的 Http+Ajax 请求无法实现的逆向推送效果。
5.3. 前端代码
function WebSocketTest() {
if ("WebSocket" in window) {
var ws = new WebSocket("ws://localhost:7000/hello2");
//发送数据
ws.onopen = function() {
ws.send("发送数据");
};
//接受数据
ws.onmessage = function(evt) {
var received_msg = evt.data;
console.log(">>>"+received_msg)
};
//监听连接关闭
ws.onclose = function() {
alert("连接已关闭...");
};
} else {
alert("您的浏览器不支持 WebSocket!");
}
}
5.4 测试效果
浏览器控制台每隔 5s 钟就能收到服务端推送过来的消息,如下图所示:
6. 小结
- 我们需要了解 WebSocket 的应用方向,主要是前端和服务端建立长连接通信;
- 掌握 WebSocket 几个事件监听方法,open ()、message ()、error ()、close ();
- 掌握 Netty 编写的服务端写法,主要是几个类 HttpServerCodec、ChunkedWriteHandler、HttpObjectAggregator、WebSocketServerProtocolHandler,Handler 业务跟普通业务没啥区别
猜你喜欢
- 2025-05-16 放弃 Websocket 使用 SSE 才发现这些功能两三行代码就搞定了
- 2025-05-16 我与spring webSocket不得不说的事
- 2025-05-16 从零搭建体育比分网站完整步骤
- 2025-05-16 「项目实战」.待办事项之WebSocket Web客户端(一)
- 2025-05-16 springboot 2整合websocket推送消息、数据流、解析pdf图片并压缩
- 2025-05-16 Springboot 整合 Websocket 轻松实现IM及时通讯
- 2025-05-16 现在页面实时聊天都使用Websocket技术实现吗?
- 2025-05-16 Trae验证websocket版本功能
- 2025-05-16 Spring Boot3 竟能如此轻松整合 WebSocket 技术,你还不知道?
- 2025-05-16 Springboot下的WebSocket开发
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端md5加密 (49)
- 前端路由 (55)
- 前端数组 (65)
- 前端定时器 (47)
- 前端接口 (46)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle约束 (46)
- oracle 中文 (51)
- oracle链接 (47)
- oracle的函数 (57)
- mac oracle (47)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)