WebSocket+Netty构建web聊天程序(一)

简介: WebSocket+Netty构建web聊天程序(一)

WebSocket#


传统的浏览器和服务器之间的交互模式是基于请求/响应的模式,虽然可以使用js发送定时任务让浏览器在服务器中拉取但是弊端很明显,首先就是不能避免的延迟,其次就是频繁的请求,让服务器的压力骤然提升


WebSocket是H5新增的协议,用于构建浏览器和服务器之间的不受限的长连接的通信模式,不再局限于请求/响应式的模型,服务端可以主动推送消息给客户端,(游戏有某个玩家得奖了的弹幕)基于这个特性我们可以构建我们的实时的通信程序


协议详情:#


websocket建立连接时,是通过浏览器发送的HTTP请求,报文如下:


GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13


  • 首先GET请求是以 ws开头的
  • 其中请求头中的Upgrade: websocket Connection: Upgrade表示尝试建立WebSocket连接


对于服务端的相应数据


HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string


其中的101,表示服务端支持WebSocket协议, 双方基于Http请求,成功建立起WebSocket连接,双方之间的通信也不再通过HTTP


JS对WebSocket的封装对象#


对于JS的WebSocket对象来说,它常用 4个回调方法,以及两个主动方法


方法名 作用
onopen() 和服务端成功建立连接后回调
onmessage(e) 收到服务端的的消息后回调,e为消息对象
onerror() 链接出现异常回调,如服务端关闭
onclose() 客户端单方面断开连接时回调
send(e) 主动向服务端推送消息
close() 主动关闭通道


再次对WebSocket进行封装#


知道了回调函数回调时机,我们接下来要做的就是在他的整个生命周期的不同回调函数中,添加我们指定的动作就ok了,下面是通过Window定义一个全局的聊天对象CHAT


window.CHAT={
var socket = null;
// 初始化socket
init:function(){
// 判断当前的浏览器是否支持WebSocket
if(window.WebSocket){
  // 检验当前的webSocket是否存在,以及连接的状态,如已经连接,直接返回
  if(CHAT.socket!=null&&CHAT.socket!=undefined&&CHAT.socket.readyState==WebSocket.OPEN){
    return false;
  }else{// 实例化 , 第二个ws是我们可以自定义的, 根据后端的路由来
    CHAT.socket=new WebSocket("ws://192.168.43.10:9999/ws");
    // 初始化WebSocket原生的方法
    CHAT.socket.onopen=CHAT.myopen();
    CHAT.socket.onmessage=CHAT.mymessage();
    CHAT.socket.onerror=CHAT.myerror();
    CHAT.socket.onclose=CHAT.myclose(); 
  }
}else{
  alert("当前设备不支持WebSocket");
}
}
// 发送聊天消息
chat:function(msg){
  // 如果的当前的WebSocket是连接的状态,直接发送 否则从新连接
  if(CHAT.socket.readyState==WebSocket.OPEN&&CHAT.socket!=null&&CHAT.socket!=undefined){
    socket.send(msg);
  }else{
    // 重新连接
    CHAT.init();
    // 延迟一会,从新发送
    setTimeout(1000);
    CHAT.send(msg);
  }
}
// 当连接建立完成后对调
myopen:function(){
  // 拉取连接建立之前的未签收的消息记录
  // 发送心跳包
}
mymessage:function(msg){
  // 因为服务端可以主动的推送消息,我们提前定义和后端统一msg的类型, 如,拉取好友信息的消息,或 聊天的消息
  if(msg==聊天内容){
  // 发送请求签收消息,改变请求的状态
  // 将消息缓存到本地
  // 将msg 转换成消息对象, 植入html进行渲染
  }else if(msg==拉取好友列表){
  // 发送请求更新好友列表
  }
}
myerror:function(){
  console.log("连接出现异常...");
}
myclose:function(){
  console.log("连接关闭...");
}
keepalive: function() {
  // 构建对象
  var dataContent = new app.DataContent(app.KEEPALIVE, null, null);
  // 发送心跳
  CHAT.chat(JSON.stringify(dataContent));
  // 定时执行函数, 其他操作
    // 拉取未读消息
    // 拉取好友信息
}
}


对消息类型的约定#


WebSocket对象通过send(msg);方法向后端提交数据,常见的数据如下:

  • 客户端发送聊天消息
  • 客户端签收消息
  • 客户端发送心跳包
  • 客户端请求建立连接


为了使后端接收到不同的类型的数据做出不同的动作, 于是我们约定发送的msg的类型;


// 消息action的枚举,这个枚举和后端约定好,统一值
CONNECT: 1,   // 第一次(或重连)初始化连接
CHAT: 2,    // 聊天消息
SIGNED: 3,    // 消息签收
KEEPALIVE: 4,   // 客户端保持心跳
PULL_FRIEND:5,  // 重新拉取好友
// 消息模型的构造函数
ChatMsg: function(senderId, receiverId, msg, msgId){
  this.senderId = senderId;
  this.receiverId = receiverId;
  this.msg = msg;
  this.msgId = msgId;
}
//  进一步封装两个得到最终版消息模型的构造函数
DataContent: function(action, chatMsg, extand){
  this.action = action;
  this.chatMsg = chatMsg;
  this.extand = extand;
}


如何发送数据?#


我们使用js,给发送按钮绑定点击事件,一经触发,从缓存中获取出我们需要的参数,调用


CHAT.chat(Json.stringify(dataContent));


后端netty会解析dataContent的类型,进一步处理


如何签收未与服务器连接时好友发送的消息?#


  • 消息的签收时机:
    之所以会有未签收的信息,是因为客户端未与服务端建立WebSocket连接, 当服务端判断他维护的channel组中没有接受者的channel时,不会发送数据,而是把数据持久化到数据库,并且标记flag=未读, 所以我们签收信息自然放在客户端和服务端建立起连接时的回调函数中执行
  • 步骤:
  • 客户端通过js请求,拉取全部的和自己相关的flag=未读的消息实体列表
  • 从回调函数数中,把列表中的数据取出,缓存在本地
  • 将列表中的数据回显在html页面中
  • 和后端约定,将该列表中所有的实例的id取出,用逗号分隔拼接成字符串, 以action=SIGNED的方式发送给后端,让其进行签收


相关文章
|
12天前
|
网络协议 应用服务中间件 网络安全
odoo17在线聊天报错提示 Couldn‘t bind the websocket...
当 Odoo 17 报错 "Couldn't bind the websocket..." 时,通过检查和配置 WebSocket 端口、防火墙规则、代理服务器以及 Odoo 配置文件,可以有效解决此问题。确保每一步操作准确无误,最终重启相关服务,使配置生效。希望这些步骤能帮助您快速恢复 Odoo 的在线聊天功能。
28 1
|
21天前
|
监控 前端开发 JavaScript
使用 MERN 堆栈构建可扩展 Web 应用程序的最佳实践
使用 MERN 堆栈构建可扩展 Web 应用程序的最佳实践
27 6
|
23天前
|
存储 缓存 前端开发
Web端IM聊天消息该不该用浏览器本地存储?一文即懂!
鉴于目前浏览器技术的进步(主要是HTML5的普及),在Web网页端IM聊天应用的技术选型阶段,很多开发者都会纠结到底该不该像原生移动端IM那样将聊天记录缓存在浏览器的本地,还是像传统Web端即时通讯那样继续存储在服务端?本文将为你简洁明了地讲清楚浏览器本地存储技术(Web Storage),然后你就知道到底该怎么选择了。
26 1
|
27天前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
|
28天前
|
缓存 监控 前端开发
在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统
本文深入探讨了在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统。
79 1
|
1月前
|
数据可视化 数据库 开发者
使用Dash构建交互式Web应用程序
【10月更文挑战第16天】本文介绍了使用Python的Dash框架构建交互式Web应用程序的方法。Dash结合了Flask、React和Plotly等技术,让开发者能够快速创建功能丰富的数据可视化应用。文章从安装Dash开始,逐步介绍了创建简单应用程序、添加交互元素、部署应用程序以及集成更多功能的步骤,并提供了代码示例。通过本文,读者可以掌握使用Dash构建交互式Web应用程序的基本技巧和高级功能。
59 3
|
1月前
|
Kubernetes Cloud Native JavaScript
为使用WebSocket构建的双向通信应用带来基于服务网格的全链路灰度
介绍如何使用为基于WebSocket的云原生应用构建全链路灰度方案。
|
2月前
|
JavaScript 前端开发
如何使用Vue.js构建响应式Web应用程序
【10月更文挑战第9天】如何使用Vue.js构建响应式Web应用程序
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
159 3
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
172 45
下一篇
DataWorks