Netty高级进阶之基于Netty的Websocket开发网页聊天室
本通过实战演练,学习了如何基于Netty的websocket开发一个网页聊天室。
Netty高级进阶之基于Netty的Websocket开发网页聊天室
Webdocket简介
Websockt是一种在单个TCP连接上进行全双工通信的协议。
Websocket使客户端和服务端的数据交互变得简单,允许服务器主动向客户端推送数据。
在Websocket API中,客户端只需要与服务器完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。
他的应用场景如下:
- 社交订阅
- 协同编辑/编程
- 股票基金报价
- 体育实况更新
- 多媒体聊天
- 在线教育
Websocket和HTTP的区别
HTTP协议是应用层的协议,是基于TCP协议的。
HTTP协议必须经过三次握手才能发送消息。
HTTP连接分为短连接和长链接。短连接是每次都要经过三次握手才能发送消息。就是说每一个request对应一个response。长连接在一定期限内保持TCP连接不断开。
客户端与服务器通信,必须由客户端先发起,然后服务端返回结果。客户端是主动的,服务端是被动的。
客户端想要实时获取服务端的消息,就要不断发送长连接到服务端。
Websocket实现了多路复用,它是全双工通信。在Websocket协议下,服务端和客户端可以同时发送消息。
建立了Websocket连接之后,服务端可以主动给客户端发送消息。信息中不必带有header的部分信息,与HTTP长连接通信对比,这种方式降低了服务器的压力,信息当中也减少了多余的信息。
导入基础环境
新建netty-springboot项目
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zt5trjYz-1651644006392)(https://cdn.jsdelivr.net/gh/terwer/upload/img/image-20220430225632849.png)]
导入依赖模块
<dependencies><!-- 模板引擎 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- web模块 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency> </dependencies>
导入静态资源
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uiAqciq1-1651644006394)(https://cdn.jsdelivr.net/gh/terwer/upload/img/image-20220430230249496.png)]
配置yaml
server:port: 8080 resources:static-locations:- classpath:/static/ spring:thymeleaf:cache: falsechecktemplatelocation: trueenabled: trueencoding: UTF-8mode: HTMLprefix: classpath:/templates/suffix: .html
关于Springboot整合thymeleaf的404问题,参考:
/post/404-problem-with-springboot-configuration-thymeleaf.html
代码实现
服务端开发
添加Netty相关依赖
<!--引入netty依赖 --> <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId> </dependency>
Netty相关配置
netty:port: 8081ip: 127.0.0.1path: /chat
Netty配置类
/*** Netty配置类** @name: NettyConfig* @author: terwer* @date: 2022-05-01 00:04**/ @Component @Data @ConfigurationProperties(prefix = "netty") public class NettyConfig {// netty监听端口private int port;// webdocket访问路径private String path; }
Netty的WebsocketServer开发
/*** Netty的Websocket服务器** @name: NettyWebsocketServer* @author: terwer* @date: 2022-05-01 00:11**/ @Component public class NettyWebsocketServer implements Runnable {@Autowiredprivate NettyConfig nettyConfig;@Autowiredprivate WebsocketChannelInit websocketChannelInit;private NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);private NioEventLoopGroup workerGroup = new NioEventLoopGroup();@Overridepublic void run() {try {// 1.创建服务端启动助手ServerBootstrap serverBootstrap = new ServerBootstrap();// 2.设置线程组serverBootstrap.group(bossGroup, workerGroup);// 3.设置参数serverBootstrap.channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.DEBUG)).childHandler(websocketChannelInit);// 4.启动服务端ChannelFuture channelFuture = serverBootstrap.bind(nettyConfig.getPort()).sync();System.out.println("------Netty服务端启动成功------");channelFuture.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();throw new RuntimeException(e);} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}/*** 关闭资源-容器销毁时候关闭*/@PreDestroypublic void close() {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();} }
通道初始化对象
/*** 通道初始化对象** @name: WebsocketChannelInit* @author: terwer* @date: 2022-05-01 23:11**/ @Component public class WebsocketChannelInit extends ChannelInitializer {@Autowiredprivate NettyConfig nettyConfig;@Autowiredprivate WebsocketHandler websocketHandler;@Overrideprotected void initChannel(Channel channel) throws Exception {ChannelPipeline pipeline = channel.pipeline();// 对HTTP协议的支持pipeline.addLast(new HttpServerCodec());// 对大数据流的支持pipeline.addLast(new ChunkedWriteHandler());// post请求分为三个部分:request line/request header/message body// 对POST请求的支持,将多个信息转化成单一的request/response对象pipeline.addLast(new HttpObjectAggregator(8000));// 对WebSocket协议的支持// 将http协议升级为ws协议pipeline.addLast(new WebSocketServerProtocolHandler(nettyConfig.getPath()));// 自定义处理handlerpipeline.addLast(websocketHandler);} }
处理对象
/*** 自定义Websocket处理类* Websocket数据以帧的形式进行处理* 需要设置通道共享** @name: WebsocketHandler* @author: terwer* @date: 2022-05-01 23:21**/ @Component @ChannelHandler.Sharable public class WebsocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {public static List<Channel> channelList = new ArrayList<>();/*** 通道就绪事件** @param ctx* @throws Exception*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();// 有客户端连接时,将通道放入集合channelList.add(channel);System.out.println("有新的链接");}/*** 通道未就绪** @param ctx* @throws Exception*/@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {// channel下线Channel channel = ctx.channel();// 客户端连接端口,移除连接channelList.remove(channel);System.out.println("连接断开");}/*** 通道读取事件** @param ctx* @param textWebSocketFrame* @throws Exception*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame textWebSocketFrame) throws Exception {String msg = textWebSocketFrame.text();System.out.println("接收到消息:" + msg);// 当前发送消息的通道Channel channel = ctx.channel();for (Channel channel1 : channelList) {// 排除自身通道if (channel != channel1) {channel1.writeAndFlush(new TextWebSocketFrame(msg));}}}/*** 异常处理事件** @param ctx* @param cause* @throws Exception*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();Channel channel = ctx.channel();System.out.println("消息发送异常。");// 移除channelList.remove(channel);} }
注意:处理类需要设置成共享的
启动类
@SpringBootApplication public class NettySpringbootApplication implements CommandLineRunner {@Autowiredprivate NettyWebsocketServer nettyWebsocketServer;public static void main(String[] args) {SpringApplication.run(NettySpringbootApplication.class, args);}@Overridepublic void run(String... args) throws Exception {new Thread(nettyWebsocketServer).start();} }
前端js开发
建立连接
var ws = new WebSocket("ws://localhost:8081/chat"); ws.onopen = function () {console.log("连接成功") }
发送消息
function sendMsg() {var message = $("#my_test").val();$("#msg_list").append(`<li class="active"}><div class="main self"><div class="text">` + message + `</div></div></li>`);$("#my_test").val('');//发送消息message = username + ":" + message;ws.send(message);// 置底setBottom(); }
接收消息
ws.onmessage = function (evt) {showMessage(evt.data); }function showMessage(message) {// 张三:你好var str = message.split(":");$("#msg_list").append(`<li class="active"}><div class="main"><img class="avatar" width="30" height="30" src="/img/user.png"><div><div class="user_name">${str[0]}</div><div class="text">${str[1]}</div></div> </div></li>`);// 置底setBottom(); }
关闭与错误处理
ws.onclose = function (){console.log("连接关闭") }ws.onerror = function (){console.log("连接异常") }
运行效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KaNmXdr-1651644006395)(https://cdn.jsdelivr.net/gh/terwer/upload/img/image-20220502001145851.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oZW1k4P5-1651644006395)(…/…/…/…/…/…/…/Library/Application Support/typora-user-images/image-20220502001159603.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d5woRo7z-1651644006396)(https://cdn.jsdelivr.net/gh/terwer/upload/img/image-20220502001220081.png)]
Netty高级进阶之基于Netty的Websocket开发网页聊天室相关推荐
- Java和WebSocket开发网页聊天室
一.项目简介 WebSocket是HTML5一种新的协议,它实现了浏览器与服务器全双工通信,这里就将使用WebSocket来开发网页聊天室,前端框架会使用AmazeUI,后台使用Java,编辑器使用U ...
- java web 聊天室_Java和WebSocket开发网页聊天室
小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ 一.项目简介WebSocket是HTML5一种新的 ...
- 基于Node.js + WebSocket 的简易聊天室
代码地址如下: http://www.demodashi.com/demo/13282.html Node.js聊天室运行说明 Node.js的本质就是运行在服务端的JavaScript.Node.j ...
- 基于WebSocket实现网页聊天室
背景 在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 ...
- 使用WebSocket实现网页聊天室
使用WebSocket实现网页聊天室 一.文章导读 服务器推送你还在使用轮询吗?本文将带你领略WebSocket的魅力,轻松实现服务器推送功能.本文将以下面两方面让你理解WebSocket并应用到具体 ...
- 如何使用WebSocket实现网页聊天室?
一.文章导读 服务器推送你还在使用轮询吗?本文将带你领略WebSocket的魅力,轻松实现服务器推送功能.本文将以下面两方面让你理解WebSocket并应用到具体的开发中 WebSocket概述 使用 ...
- Android基于XMPP Smack openfire 开发的聊天室
公司刚好让做即时通讯模块,服务器使用openfire,偶然看到有位仁兄的帖子,拷贝过来细细研究,感谢此仁兄的无私,期待此仁兄的下次更新 转自http://blog.csdn.net/lnb333666 ...
- java+websocket实现网页聊天室
核心技术websocket 前提 1.tocmat7.02版本以上 2.浏览器支持websocket通讯 3.这个是html5的功能 客户端和服务器建立连接 jsp/html页面 1.浏览器和后台服务 ...
- php即时聊天的框架_workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)...
workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...
- workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)...
workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...
最新文章
- C++从零实现神经网络(收藏版:两万字长文)
- html中隐藏溢出怎么写,html-如何隐藏表行溢出?
- javascript刷新页面的集中办法
- spark Bisecting k-means(二分K均值算法)
- (转)跟我一起写 Makefile(一)(陈皓)
- AI助力新药研发 腾讯发布「云深智药」平台
- How is assignment blocks of overview pages read from configuration
- python3高级 一 迭代器
- three.js 实现图片粒子爆炸特效
- 百度知识图谱技术及应用
- 从最理想的情况论证自己的观点,必然错误,为什么明知故犯?
- Bongiovi DPS for Mac(优秀的声音增强软件)
- 摄像机和镜头的基础知识
- asf格式如何转换为mp4?
- 关于Windows 2003 安装Inter G33/G31 显卡问题
- 项目-1.CROSSFORMER论文与代码解析(CrossFormer: A Versatile Vision Transformer Based on Cross-scale Attention)
- 《李尔王》:重拾李尔王的话语权力
- word 文本差异比较
- 美颜API是什么意思?美颜API和美颜SDK有什么区别?
- AEC IATF16949 - AEC-Qxxx 质量体系IATF16949 -芯片进入汽车领域的门槛
热门文章
- [CityHunter]游戏流程设计及技术要点
- c语言2059,C语言错误 error C2059: 语法错误:“)”以及 错误error C2065: “sockaddr”: 未声明的标识符...
- eclipse maven 安装
- RecycleView 删除指定item
- colorbox 自适应 高度
- springboot基于web儿童教育网站111123
- 网站性能优化--实例分析篇
- 腾讯IM发送消息20001
- 大学计算机专业学习哪些课程?
- iOS load和initialize方法详解