本通过实战演练,学习了如何基于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长连接通信对比,这种方式降低了服务器的压力,信息当中也减少了多余的信息

导入基础环境

  1. 新建netty-springboot项目

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zt5trjYz-1651644006392)(https://cdn.jsdelivr.net/gh/terwer/upload/img/image-20220430225632849.png)]

  2. 导入依赖模块

    <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>
    
  3. 导入静态资源

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uiAqciq1-1651644006394)(https://cdn.jsdelivr.net/gh/terwer/upload/img/image-20220430230249496.png)]

  4. 配置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

代码实现

服务端开发

  1. 添加Netty相关依赖

    <!--引入netty依赖 -->
    <dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId>
    </dependency>
    
  2. Netty相关配置

    netty:port: 8081ip: 127.0.0.1path: /chat
    
  3. 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;
    }
    
  4. 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();}
    }
    
  5. 通道初始化对象

    /*** 通道初始化对象** @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);}
    }
    
  6. 处理对象

    /*** 自定义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);}
    }
    

    注意:处理类需要设置成共享的

  7. 启动类

    @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开发网页聊天室相关推荐

  1. Java和WebSocket开发网页聊天室

    一.项目简介 WebSocket是HTML5一种新的协议,它实现了浏览器与服务器全双工通信,这里就将使用WebSocket来开发网页聊天室,前端框架会使用AmazeUI,后台使用Java,编辑器使用U ...

  2. java web 聊天室_Java和WebSocket开发网页聊天室

    小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ 一.项目简介WebSocket是HTML5一种新的 ...

  3. 基于Node.js + WebSocket 的简易聊天室

    代码地址如下: http://www.demodashi.com/demo/13282.html Node.js聊天室运行说明 Node.js的本质就是运行在服务端的JavaScript.Node.j ...

  4. 基于WebSocket实现网页聊天室

    背景 在浏览器中通过http仅能实现单向的通信,comet可以一定程度上模拟双向通信,但效率较低,并需要服务器有较好的支持; flash中的socket和xmlsocket可以实现真正的双向通信,通过 ...

  5. 使用WebSocket实现网页聊天室

    使用WebSocket实现网页聊天室 一.文章导读 服务器推送你还在使用轮询吗?本文将带你领略WebSocket的魅力,轻松实现服务器推送功能.本文将以下面两方面让你理解WebSocket并应用到具体 ...

  6. 如何使用WebSocket实现网页聊天室?

    一.文章导读 服务器推送你还在使用轮询吗?本文将带你领略WebSocket的魅力,轻松实现服务器推送功能.本文将以下面两方面让你理解WebSocket并应用到具体的开发中 WebSocket概述 使用 ...

  7. Android基于XMPP Smack openfire 开发的聊天室

    公司刚好让做即时通讯模块,服务器使用openfire,偶然看到有位仁兄的帖子,拷贝过来细细研究,感谢此仁兄的无私,期待此仁兄的下次更新 转自http://blog.csdn.net/lnb333666 ...

  8. java+websocket实现网页聊天室

    核心技术websocket 前提 1.tocmat7.02版本以上 2.浏览器支持websocket通讯 3.这个是html5的功能 客户端和服务器建立连接 jsp/html页面 1.浏览器和后台服务 ...

  9. php即时聊天的框架_workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)...

    workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...

  10. workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)...

    workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...

最新文章

  1. C++从零实现神经网络(收藏版:两万字长文)
  2. html中隐藏溢出怎么写,html-如何隐藏表行溢出?
  3. javascript刷新页面的集中办法
  4. spark Bisecting k-means(二分K均值算法)
  5. (转)跟我一起写 Makefile(一)(陈皓)
  6. AI助力新药研发 腾讯发布「云深智药」平台
  7. How is assignment blocks of overview pages read from configuration
  8. python3高级 一 迭代器
  9. three.js 实现图片粒子爆炸特效
  10. 百度知识图谱技术及应用
  11. 从最理想的情况论证自己的观点,必然错误,为什么明知故犯?
  12. Bongiovi DPS for Mac(优秀的声音增强软件)
  13. 摄像机和镜头的基础知识
  14. asf格式如何转换为mp4?
  15. 关于Windows 2003 安装Inter G33/G31 显卡问题
  16. 项目-1.CROSSFORMER论文与代码解析(CrossFormer: A Versatile Vision Transformer Based on Cross-scale Attention)
  17. 《李尔王》:重拾李尔王的话语权力
  18. word 文本差异比较
  19. 美颜API是什么意思?美颜API和美颜SDK有什么区别?
  20. AEC IATF16949 - AEC-Qxxx 质量体系IATF16949 -芯片进入汽车领域的门槛

热门文章

  1. [CityHunter]游戏流程设计及技术要点
  2. c语言2059,C语言错误 error C2059: 语法错误:“)”以及 错误error C2065: “sockaddr”: 未声明的标识符...
  3. eclipse maven 安装
  4. RecycleView 删除指定item
  5. colorbox 自适应 高度
  6. springboot基于web儿童教育网站111123
  7. 网站性能优化--实例分析篇
  8. 腾讯IM发送消息20001
  9. 大学计算机专业学习哪些课程?
  10. iOS load和initialize方法详解