《菜农升职记》之 Websocket

简介: 本文主要介绍 websocket 的使用

作为准应届生的小菜农早早的便找到了一份实习工作,初到公司一切都没那么适应,作为导师的程立这天给小菜农安排了一个需求,想要实现一个简单的《人工客服》需求,也就是即时通讯。小菜农尽管没啥经验,但为了给导师留下良好的印象便一口爽快的接下需求。


接下需求后小菜农便开始构思如何实现即时通讯,他开始在各大平台查看关于在线客服的案例~


网络异常,图片无法展示
|


他总结了下需求:在线客服,需求理解起来很简单,就相当于一个 web 的聊天页面,也就是客户端能够即时拉取到服务端的响应,尽管平时微信重度使用,但是到了自己实现的时候却满头雾水,眼看一上午的时间就要过去了,自己却没有任何进展,唯一的进展便是找到了以上那张图,却没有丝毫卵用~


中午吃完饭,其他人都已经息屏休息了,而小菜农还在电脑前为这个需求而烦恼,不由有些烦躁起来了,开始想念在学校的日子了。通过接口获取响应!前端整个定时任务去捞消息 这个奇妙的想法直接冲击菜农的大脑


"妙啊",小菜农为自己的好主意开始津津乐道起来,烦恼来得快去的也快~不由多想便开始吭哧吭哧的写起代码了,那一套可谓是行云流水


伪代码如下


服务端:


网络异常,图片无法展示
|


客户端:


setInterval(function () {
    $.ajax({
        async: false,
        url: "localhost:8080/roll",
        type: "get",
        success(data){
         console.log("success");
        }
    })
},1000)


写完后,小菜农简单验证了下,发现都功能已经满足了便开始向导师程立showcase了,程立简单地过了遍页面效果,感觉效果在预期内便让小菜农提交代码准备合并发布了

小菜农提交完代码后心中不由欢喜起来,自我感觉十分良好,能在规定时间内完成这个不是那么简单的需求,想必离自己的转正又进一步了吧!但是没等小菜农高兴太久,电脑上便闪起了导师的叮叮提示,"小菜农,现在有空吗,过来下"。不好的念头浮上小菜农的心头,"这该不会出 bug 了吧"。小菜农颤颤巍巍的来到导师的工位,"我刚刚 review 了下你的代码",原来还没发布,那就不是bug的事情了,幸好幸好~ 小菜农心中暗想。"我看了下你这个功能的实现方式,这种方式尽管能够实现需求,但是并不是很好的解决方案",导师接着说。“通过轮询的方法,尽管可以从服务端捞到聊天数据,但是接口的频繁请求缺陷也会很明显,十分浪费带宽流量,服务器的压力就会比较大,所以这种方式并不是很好的解决方法,你可以回去再想想看有没有什么其他比较好的解决方法!”


"嗯嗯,是我没考虑好,那我回去再改改!"小菜农涉世未深,导师都这样说了,那这个方案肯定得 pass,连忙接道。


小菜农回到工位后,难免有些沮丧,本来想好好表现表现,没想到自己想出的方案弊端这么多。一阵头大,现在也没时间想这件事,如何实现才是要紧之事!小菜农又陷入了沉思,这可该如何是好~


小菜农随后便打开了某度,看到了一个关键词 SSE


SSE 全称 Server-Sent Events,指的是网页自动获取来自服务器的更新,也就是自动化获取服务端推送至网页的数据,这是一个 H5 的属性,除了 IE,其他标准浏览器基本都兼容


小菜农认真研究了下,发现这种方式和自己之前的实现方式有些相似,但是就不需要客户端定时去获取,而是服务端向客户端声明要发送流信息,然后连续不断地发送过来。这时客户端是不会关闭连接的,会一直等这服务器发过来的新的数据流。"妙啊,这样子不就不会频繁建立连接,浪费带宽了",小菜农又兴奋了起来,这回肯定能够满足导师的需求了!小菜农又花费一个下午的时间将代码实现方式重构了一遍,便提交了~


伪代码


服务端:


网络异常,图片无法展示
|


客户端:


网络异常,图片无法展示
|


这回可别再出意外了!小菜农心中默念,但是好景不长,叮叮又开始闪烁了,这这这。。。小菜农的心态有些崩了,完了,这回试用期可能要提前结束了。


沉重都不足以形容小菜农现在的状态了,"我刚刚看了下你这种实现方式比之前改进了不少,但是我们应该还有更好的实现方式,不妨可以考虑下使用 websocket 来实现,没事不要急,咱们可以回去再好好看看"。小菜农并没有听到想象中的责怪,不由心中一暖,Websocket!这回我可要了解清楚再动手实现了,可不能想之前那样为了速度草草的实现了事 下定决心后,小菜农回到工位开始研究起了 Websocket


这次小菜农决定不再为了缩短工时而草草上线了,他打开了搜索引擎开始查找关于《Websocket》的有关资料。


什么是 websocket?


WebSocket 是一种基于 TCP 的网络协议,同时他也是一种 全双工通信的协议,既允许客户端向服务端发送消息,也允许服务器主动向客户端发送消息。在 WebSocket 中,浏览器和服务器只需要完成一次握手,两者之间就可以建立持久性的连接,进行双向数据传输


在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。


"好家伙,这简介直接概括了我的需求!秒啊~",小菜农喜出望外,天是那么的蓝~ 他迫不及待的往下看


WebSocket 有哪些特点?


1、支持双向通信,实时性更强


2、协议标识符是 ws ,如果采用类似 Https 方式的加密就需要用 wss


3、轻量级,性能开销小,通信十分高效


4、建立在 TCP 协议智商,服务端的实现比较容易


原来是这么一回事,小菜农开始分析自己前两种实现方式的弊端


1、定时轮询的方式


优点就是实现简单,想到这个小菜农老脸一红。缺点也是导师所说的,有一定延迟性,而且服务器的压力较大,浪费带宽流量,因为绝大部分的请求是无效的


2、SSE 方式


这种方式和 websocket 有些类似,但是它只能单工通信,建立连接后,只能由服务端发往客户端,且占用一个连接,如果需要客户端向服务端通信,需要额外再打开一个连接


网络异常,图片无法展示
|


通过java编写的服务端自带websocket包,编写如下:


网络异常,图片无法展示
|


客户端实现 websocket 也十分简单,只需要以下API


var Socket = new WebSocket(url, [protocol] );


第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议


在websocket 存在 4 种事件如下:


事件 事件处理程序 描述
open Socket.onopen 连接建立时触发
message Socket.onmessage 客户端接收服务端数据时触发
error Socket.onerror 通信发生错误时触发
close Socket.onclose 连接关闭时触发


代码如下:


网络异常,图片无法展示
|


到这里,websocket 通信便已经实现了,当小菜农刚要准备提交的时候,一个念头兴起,websocket 是导师给我的建议,虽然我已经完成了,但是会不会有更好的方式,能让导师眼前一亮? 想到这里,小菜农不由磨手擦拳了。一番查找,没想到还真的让他找到了,STOMP 协议~ 这应该就是我想要的了~


什么是 STOMP 协议?


STOMP (Simple Text-Orientated Messaging Protocaol) ,它是一种简单的面向文本的消息传递协议,提供了一个可互操作的连接格式,允许 STOMP 客户端向任意 STOMP 消息代理 Broker 进行交互,设计简单,易于开发


STOMP 的特点?


1、STOMP 是基于帧的协议,其 帧 是以 HTTP 为模型


2、STOMP 框架由命令,一组可选的标头和可选的主体构成


3、STOMP 基于文本,但也允许传输二进制消息


这有点牛啊,走心的感叹~


STOMP 帧是啥?


STOMP 的结构如下:


COMMAND
header1:value1
header2:value2
Body^@


发送和接收分别使用命令 SENDSUBSCRIBE,并且还可以使用destination来描述消息的内容和接受者


STOMP 的常用帧有哪些?


  • 连接相关


1、CONNECT (连接)


2、CONNECTED (成功连接)


  • 客户端相关


1、SEND(发送)


2、SUBSRIBE(订阅)


3、UNSUBSCRIBE(取消订阅)


4、BEGIN(开始)


5、COMMIT(提交)


6、ABORT(中断)


7、ACK(确认)


8、NACK(否认)


9、DISCONNECT(断开连接)


  • 服务端相关


1、MESSAGE(消息)


2、RECEIPT(接收)


3、ERROR(错误)


小菜农吭哧吭哧地整理了关于 STOMP 的笔记,那么为什么有 websocket,还需要有 stomp,stomp的出现带来了什么好处,或是解决了什么问题?。小菜农逐渐开始学会思考了,他又开始查看 stomp 的相关资料,经过一番折腾,终于找到了些答案:

WebSocket 的创建,就很类似使用 TCP 套接字传输,传输的报文是无定义的,也就是自由度很高,没有明确的约定,那么这个时候可能就需要一种高层面的应用协议来定义这些报文的语义格式,也就是说 STOMP 也是一种协议,一种作为 WebSocket 的子协议,能够保证连接的两端都遵循这些语义。


那么使用 STOMP 的好处是什么呢


1、STOMP 已经定义好了语义格式,我们就可以无需自定义


2、现成的 stomp.js 客户端,开箱即用


3、可以使用配套的消息代理进行广播,适用于多集群的情况(RabbitMQ、ActiveMQ)


了解到这里再不动手写代码就真的是在划水了,小菜农打开项目开始撸代码了~

要使用 stomp,需要先定义 stomp 的配置类


网络异常,图片无法展示
|


上面的ws就是前端的url,后端声明端点,前端进行连接。


stomp 拦截器:


网络异常,图片无法展示
|


接收客户端消息的地方:


网络异常,图片无法展示
|


发送消息:


网络异常,图片无法展示
|


到这里服务端部分的代码便已经实现了~客户端部分也很简单只需要引入两个 js 便可实现


网络异常,图片无法展示
|


这里为了在客户端接收到消息,必须要先订阅一个目的地 destination,也就是使用 subscribe()去订阅,这个方法有两个必需的参数:目的地回调函数。还有一个可选的参数 headers


当客户端与服务端连接成功后,可以调用 send()来发送STOMP消息。这个方法必须有一个参数,用来描述对应的STOMP的目的地。另外可以有两个可选的参数:headersobject类型包含额外的信息头部


到这里就已经实现了 stomp 的功能,小菜农连忙打开页面验证下成果:


网络异常,图片无法展示
|


网络异常,图片无法展示
|


   到这里,小菜农便已经实现了在线客服的功能~ 虽然小菜农实现了聊天室的功能,但实现的过程中也遇到不小的困难,得赶紧记录一下!


可以看到上面涉及到了一些关键词:


  • Message:消息,携带 header 和 payload


  • MessageHandler:处理 client 消息的实体


  • MessageChannel:解耦消息发送者与消息接收者的实体


  • clientInboudChannel:用于从 WebSocket 客户端接收消息
  • clientOutboundChannel:用于将服务器消息发送给 WebSocket 客户端
  • brokerChannel:用于从服务器,应用程序中向消息代理发送消息


  • Broker:存放消息的中间件,client 可以订阅 broker 中的消息


可以看出stomp是一种类似订阅发布模式,我们可以动态灵活的声明主题,前端可以订阅不同的主题,接收到不同主题下的消息,接触过消息队列的小伙伴肯定不会陌生~

小菜农到此便完成了《人工客服》 的需求,想到自己之前因为没有思绪而各种烦躁的行为不由尴尬一笑,所以说在遇到自己不会的时候切勿急躁,有问题还是要及时理清思路,可以多问,但不能不学~


目录
相关文章
|
3月前
|
数据采集 网络协议 Python
🔍HTTP协议不为人知的秘密:Python网络编程高手是如何炼成的?
【7月更文挑战第29天】探索HTTP协议核心—请求与响应的交互:浏览器发送请求至服务器,后者处理后返回资源数据与状态码(如200表示成功)。Python高手需理解这些机制并掌握工具如`requests`库。HTTP头信息(Headers)含元数据如`User-Agent`、`Content-Type`及`Cookie`用于会话管理。尽管HTTP无状态,但可通过`Cookie`和`Session`模拟状态保持。成为高手之路包括:深入理解协议、实践项目、阅读优秀库源码如`requests`、跟进新技术如HTTP/2与HTTP/3,并积极参与社区交流。
22 1
|
5月前
|
资源调度 JavaScript 前端开发
❤Nodejs 第十五章(简单websocket聊天实现)
【4月更文挑战第15天】本文介绍了在Node.js中实现简单WebSocket聊天的过程。首先通过`yarn`创建项目并安装`ws`和`express`依赖。接着,编写`WebSocketServer.js`建立WebSocket服务器,处理客户端连接、消息收发及错误。然后,用`server.js`创建一个静态文件服务器,提供`index.html`。`index.html`包含客户端的WebSocket连接和消息处理。启动两个服务器后,可以在浏览器中打开`index.html`进行聊天。最后,讨论了在Node.js 20+Vite环境下使用WebSocket时可能遇到的问题
57 0
|
前端开发 JavaScript 程序员
手摸手教你使用WebSocket[其实WebSocket也不难]
前言 在本篇文章之前,WebSocket很多人听说过,没见过,没用过,以为是个很高大上的技术,实际上这个技术并不神秘,可以说是个很容易就能掌握的技术,希望在看完本文之后,马上把文中的栗子拿出来自己试一试,实践出真知。 WebSocket解决了什么问题: 客户端(浏览器)和服务器端进行通信,只能由客户端发起ajax请求,才能进行通信,服务器端无法主动向客户端推送信息。 当出现类似体育赛事、聊天室、实时位置之类的场景时,客户端要获取服务器端的变化,就只能通过轮询(定时请求)来了解服务器端有没有新的信息变化。
625 1
惊艳!腾讯强推599页Netty进阶神技,完美诠释Netty
作为一个学Java的,如果没有研究过Netty,那么你只能算一个初等Java程序员。如果你想知道Nginx是怎么写出来的,如果你想知道Tomcat和Jetty是如何实现的,如果你想实现一个简单的Redis服务器,那都应该好好理解一下Netty,如果你要进阶,想了解Java服务器的深层高阶知识,Netty也绝对是一个必须要过的门槛。
|
前端开发 网络协议 程序员
你敢信一个HTTP能打趴80%面试者?
面试一年多,每当我问起面试者对HTTP的了解时,个个回答令我瞠目结舌,这些开发者都有3-5年的经验。请不要让我叫你野生程序员,是时候了解HTTP了,让我们当个正规军。
|
存储
Netty入门到超神系列-基于WebSocket开发聊天室
在很多的网站中都嵌入有聊天功能,最理想的方式就是使用WebSocket来开发,屏幕面前的你如果不清楚WebSocket的作用可以自己去百度一下,Netty提供了WebSocket支持,这篇文章将使用Netty作为服务器,使用WebSocket开发一个简易的聊天室系统。
250 0
|
移动开发 网络协议 大数据
WebSocket全部内容及项目经验(一)
在websocket未出来之前,实现实时数据更新都是采用轮询http请求实现的,很明显这种方式有很大的缺陷,一条数据就需要发一次http请求。HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。而比较新的技术去做轮询的效果是Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在Comet中,普遍采用的长链接,也会消耗服务器资源。在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
101 0
|
网络协议 JavaScript
WebSocket全部内容及项目经验(二)
Socket.readyState: 只读属性 readyState 表示连接状态。 Socket.bufferedAmount: 只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。 下面的代码展示一个使用bufferedAmount 特性每秒发送更新的例子。如果网络无法承受这一速率,它会相应作出调整。
|
前端开发 网络协议 程序员
一个HTTP能打趴80%面试者!你是其中一员吗?
大多数面试时,每当面试官问起面试者对HTTP的了解时,多数回答都会令面试官瞠目结舌,这些开发者都有3-5年的经验。请不要让别人叫你野生程序员,是时候了解HTTP了,让我们当个正规军。
|
移动开发 安全 小程序
即时通讯技术文集(第14期):WebSocket精华文章合集 [共15篇]
为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第14 期。
80 0