目录
WebSocket
握手协议
优点
效果展示
一、 确定需求方案
1、确定产品上线部署的屏幕分辨率
2、部署方式
二、整体架构设计
三、编码实现 (基于篇幅及可读性考虑,此处展示部分关键代码)
1、前端html代码 – 页面整体布局
2、前端JS代码 – Echarts option设置
3、 前端WebSocket通信
(1)建立连接
(2)连接建立成功事件
(3)监听数据事件
(4)连接断开事件
4、前端 Echarts 更新 option 中3个图表的data
5、后端python实现的httpserver服务代码
6、后端python实现的WebSocket服务代码
(1)响应客户端消息,统一为json格式
(2)主动发送消息给客户端
四、上线运行效果
五、启动命令
六、源码下载
更多精彩案例
写在前面,最近收到了小伙伴们的问题,大屏的数据传输可否不是客户端去http get获取,而是由服务器端主动推送,那要怎么实现那? 答:websocket协议。本案例讲述了 HTTP GET 和 Web Socket 两种获取数据的方式。
之前小伙伴们建议我出一些视频课程来学习Echarts,这样可以更快上手,所以我就追星赶月的录制了《Echart-0基础入门》系列课程(共14节课) ,希望小伙伴们多多支持。
话不多说,开始分享干货,欢迎讨论!QQ微信同号: 6550523
WebSocket
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
握手协议
- WebSocket 是独立的、创建在 TCP 上的协议。
- Websocket 通过HTTP/1.1 协议的101状态码进行握手。
- 为了创建Websocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程通常称为“握手”(handshaking)。
优点
- 较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少。
- 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。
- 保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。
效果展示
一、 确定需求方案
1、确定产品上线部署的屏幕分辨率
根据电脑分辨率屏幕自适应显示,F11全屏查看;
2、部署方式
B/S方式:支持Windows、Linux、Mac等各种主流操作系统;支持主流浏览器Chrome,Microsoft Edge,360等;服务器采用python语言编写,配置下python依赖即可。
二、整体架构设计
- 前端Echarts开源库:使用WebStorm编辑器;
- 后端 http服务器:基于 Python 实现,使用Pycharm或VSCode编辑器;
- 数据传输格式:JSON;
- 数据源类型:JSON文件。实际开发需求中,支持定制HTTP API接口方式或其它各种类型数据库,如PostgreSQL、MySQL、Oracle、Microsoft SQL Server、SQLite、Excel表格等。
- 数据更新方式:采用http get 轮询方式 和 WebSocket 推送方式。在实际开发需求中,采用后端数据实时更新,实时推送到前端这种方式具有实用性;
三、编码实现 (基于篇幅及可读性考虑,此处展示部分关键代码)
1、前端html代码 – 页面整体布局
<body style="background-color:#21202e"><div class="container_fluid"><div class="row_fluid" id="vue_app"><div style="padding:2px; background-color:#292835;" class="col-xs-12 col-md-12"><div style="padding: 0 0" class="col-xs-12 col-md-4"><dv-decoration-1 style="width:80%;height:8%;" /></div><div style="padding: 0 0;text-align: center;" class="col-xs-12 col-md-4"><div style="padding: 0; height:8%;" ><h3 id="container_0" style="color:#17c0ff; " ></h3></div></div><div style="padding: 0 0; text-align: right;" class="col-xs-12 col-md-4"><dv-decoration-1 style="width:80%;height:8%;" /></div></div><div style="padding:0;" class="col-xs-12 col-md-4"><div style="padding:2px;" class="col-xs-12 col-md-6"><div style="padding:5%; height:26%; background-color:#292835; " id="container_1"></div></div><div style="padding:2px;" class="col-xs-12 col-md-6"><div style="padding: 5%; height:26%;background-color:#292835;" id="container_2"></div></div><div style="padding:2px;" class="col-xs-12 col-md-6"><div style="padding: 5%; height:26%; background-color:#292835;" id="container_3"></div></div><div style="padding:2px;" class="col-xs-12 col-md-6"><div style="padding: 5%; height:26%; background-color:#292835;" id="container_4"></div></div></div><div style="padding:0px;" class="col-xs-12 col-md-4"><div style="padding:2px; " class="col-xs-12 col-md-12"><div style="padding:3%; height:52.8%; background-color:#292835; " id="container_5"></div></div></div><div style="padding: 0;" class="col-xs-12 col-md-4"><!-- <div style="padding: 2px; " class="col-xs-12 col-md-12"><div style="padding:5%; height:26%;background-color:#292835;" id="container_6"></div></div> --><div style="padding: 2px; " class="col-xs-12 col-md-12"><div style="padding:5%;height:52.8%;background-color:#292835;" id="container_7"></div></div></div><div style="padding:0;" class="col-xs-12 col-md-12"><div style="padding:2px;" class="col-xs-12 col-md-2"><div style="padding: 5%; height:40%;background-color:#292835;" id="container_8"></div></div><div style="padding:2px;" class="col-xs-12 col-md-2"><div style="padding: 5%;height:40%;background-color:#292835;" id="container_9"></div></div><div style="padding:2px;" class="col-xs-12 col-md-2"><div style="padding: 5%;height:40%;background-color:#292835;" id="container_10"></div></div><div style="padding:2px;" class="col-xs-12 col-md-3"><div style="padding: 5%;height:40%;background-color:#292835;" id="container_11"></div></div><div style="padding:2px;" class="col-xs-12 col-md-3"><div style="padding: 5%;height:40%;background-color:#292835;" id="container_12"></div></div></div></div></div></body>
2、前端JS代码 – Echarts option设置
option = {title: {text: '微信公众号',left: 'left',textStyle: {color: '#17c0ff',fontSize: '12'}},tooltip: {trigger: 'axis',axisPointer: {type: 'cross',label: {backgroundColor: '#6a7985'}}},legend: {data: ['总粉丝数', '活跃粉丝数', '昨日净增粉丝数'],top: '10%',left: 'center',textStyle: {color: '#fff'},},toolbox: {feature: {saveAsImage: {}}},grid: {left: '3%',right: '4%',bottom: '3%',top: '35%',containLabel: true},xAxis: [{type: 'category',boundaryGap: false,data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']}],yAxis: [{type: 'value'}],series: [{name: '昨日净增粉丝数',type: 'line',stack: '总量',areaStyle: {},emphasis: {focus: 'series'},data: []},{name: '活跃粉丝数',type: 'line',stack: '总量',areaStyle: {},emphasis: {focus: 'series'},data:[]},{name: '总粉丝数',type: 'line',stack: '总量',label: {show: true,position: 'top'},areaStyle: {},emphasis: {focus: 'series'},data: []}]};
3、 前端WebSocket通信
微信公众号 模块(area_stack.js) 图表使用了WebSocket方式主动推送数据到前端
(1)建立连接
// 第2种 web socket 方式: Echarts area_stackedvar ws = new WebSocket('ws://127.0.0.1:8888');
(2)连接建立成功事件
// 建立 web socket 连接成功触发事件ws.onopen = function () {// 连接成功后发送登录消息login = {"req":"login","id":"wsdemo"}ws.send(JSON.stringify(login));};
(3)监听数据事件
//接收消息的回调方法ws.onmessage = function (event) {//解析成 jsondata = JSON.parse(event.data)console.log(data.rsp, data.data);//更新echarts图表if(data.rsp == 'area_stacked') {wsSetOption_12(data.data);}}
(4)连接断开事件
//断开 web socket 连接成功触发事件ws.onclose = function () {ws.close();};});
4、前端 Echarts 更新 option 中3个图表的data
function wsSetOption_12(data) {console.log(data.length)var myChart = echarts.init(document.getElementById(idContainer_12));myChart.setOption({series: [{ data: data[0] }, { data: data[1] }, { data: data[2] }],});}
5、后端python实现的httpserver服务代码
def HttpServer():try:server = HTTPServer((ip, port), MyRequestHandler)listen = "http://%s:%d" % (ip, port)print("服务器监听地址: ", listen)server.serve_forever()except ValueError as e:print("Exception", e)server.socket.close()
6、后端python实现的WebSocket服务代码
# 监听ip ,端口 注册 ws_on 函数async def main():async with serve(ws_on, "127.0.0.1", 8888):await asyncio.Future() # run forever
(1)响应客户端消息,统一为json格式
async def ws_on(ws):async for message in ws:data = json.loads(message)print("服务器收到消息:", data)# 登录验证后对连接做标记, 保存到 websockets_list 字典中if data["req"] == "login":id = data["id"]print("客户端登录: ", id)websockets_list[id] = ws# 处理其他数据else:handle(data)data["rsp"] = "ok"await ws.send("服务器响应消息:" + json.dumps(data))print("服务器响应消息:", data)
(2)主动发送消息给客户端
async def ws_send():while 1:ws= Nonedata = {}try:ws = websockets_list[id_wsdemo]data["rsp"] = "area_stacked"data["data"] = get_json("myjson/area_stacked.json")await ws.send(json.dumps(data))print("已发送:", data)except Exception as e:print("不存在的websocket:", e)await asyncio.sleep(2)
四、上线运行效果
五、启动命令
<!-- 启动server命令 -->python httpserver.py<!-- 浏览器中输入网址查看大屏(端口为 httpserver.py 中的 port 参数定义) -->http://localhost:88xx<!-- 更多资料参考我的博客主页 -->https://yydatav.blog.csdn.net/<!-- 更多案例参考 -->https://blog.csdn.net/lildkdkdkjf/article/details/120705616
六、源码下载
24【源码】数据可视化:基于Echarts+Python动态实时大屏范例-WebSocket协议.zip-企业管理文档类资源-CSDN下载
注:源码包括python的httpserver + Websocket + ECharts
本次分享结束,欢迎讨论!QQ微信同号: 6550523
更多精彩案例
YYDatav的数据可视化《精彩案例汇总》_YYDataV的博客-CSDN博客