WebSocket 是 HTML5 一种新的协议,实现了浏览器与服务器之间的全双工通信。
为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,其中附加头信息"Upgrade: WebSocket"表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。
其本质是先通过 HTTP/HTTPS 协议进行握手后创建一个用于交换数据的 TCP 连接,服务端与客户端通过此 TCP 连接进行数据的双向实时传输,直到有一方主动发送关闭连接请求或出现网络错误才会关闭连接。
下面来一个ThingJS中的WebSocket数据对接示例,点击【开启读取】进行数据读取,读取到的数据将在数据详情面板进行显示,当温度值大于20℃时,车辆设置红色效果,点击【关闭读取】停止数据读取。
- var app; // App对象
- var timer; // 定时器
- var webSocket;
-
- // 引入样式文件
- THING.Utils.dynamicLoad(['/guide/examples/css/measure/panel.css'], function() {
- app = new THING.App({
- url: 'https://www.thingjs.com/static/models/storehouse'
- });
-
- app.on('load', function() {
- // 设置摄像机位置和目标点
- app.camera.position = [44.38316010361372, 22.256383671664036, 37.42310488848945];
- app.camera.target = [19.488379488180318, 0.17527928595920675, 5.827049588512047];
-
- var car = app.query('car01')[0];
- // 物体身上创建monitorData对象 用于存储动态监控数据
- car.monitorData = {
- '温度': ''
- };
-
- new THING.widget.Button('开启读取', function() {
- updateData(car);
- });
-
- new THING.widget.Button('关闭读取', function() {
- stopUpdate();
- });
-
- createHtml();
- initThingJsTip("WebSocket 实现了数据的实时双向通信。且通信不受同源策略的限制,不存在跨域问题。<br>点击【开启读取】进行数据读取,读取到的数据将在数据详情面板进行显示,当温度值大于20℃时,车辆设置红色效果,点击【关闭读取】停止数据读取!");
- })
- })
-
- // 创建html界面
- function createHtml() {
- // 数据详情界面
- let dataDetails =
- `<div id="dataDetails" class="tj-panel property-panel tj-has-title tj-sizable tj-property-panel tj-pinned" style="position: absolute; right: 10px; top: 220px; width: 315px; height: 416px; transform: none;">
- <div class="tj-close"></div>
- <div class="tj-title" style="cursor: move; user-select: none;">数据详情</div>
- <div class="tj-panel-body" style="padding-top: 0px;">
- <div class="tj-panel-container tj-scroll-bar">
- <table class="tj-table">
- <div class="empty">暂无数据</div>
- </table>
- </div>
- </div>
- </div>`;
- $('#div2d').append(dataDetails);
- // 点击按钮关闭面板
- $('#dataDetails .tj-close').on('click', function() {
- $('#dataDetails').css('display', 'none');
- });
- }
-
- /**
- * 数据对接
- */
- function updateData(obj) {
-
- // 对接自有websoket服务器
- if (!webSocket) {
-
- // 如果 ThingJS 网站是 https 则对应 wss
- // 如果 ThingJS 网站是 http 则对应 ws 即可
- webSocket = new WebSocket('wss://3dmmd.cn/wss');
- // 建立 websocket 连接成功触发事件
- webSocket.onopen = function() {
- console.log("websoket服务器连接成功...");
- };
-
- // 接收服务端数据时触发事件
- webSocket.onmessage = function(evt) {
- var data = evt.data;
- nowDatetime();
- if (($('.empty').length)) {
- $('.empty').remove();
- }
- if (!($('.tj-group').length)) {
- let tbody = `<tbody class="tj-group" id="tb-line"></tbody>`;
- $('.tj-table').prepend(tbody);
- }
- let tr =
- `<tr class="tj-group-content">
- <td class="tj-key">` + dateString + `</td>
- <td class="tj-value">` + data + `℃</td>
- </tr>`;
- $('.tj-group').prepend(tr);
- // 设置物体身上的监控数据
- obj.setAttribute("monitorData/温度", data);
- changeColor(obj);
- };
-
- webSocket.onclose = function(evt) {
- console.log("websoket关闭...");
- webSocket = null;
- }
- }
- }
-
- /**
- * 关闭数据请求
- */
- function stopUpdate() {
- // 关闭连接
- webSocket.close();
- }
-
- /**
- * 取得系统日期
- */
- function nowDatetime() {
- var date = new Date();
- var hours = (date.getHours()) > 9 ? (date.getHours()) : "0" + (date.getHours());
- var minutes = (date.getMinutes()) > 9 ? (date.getMinutes()) : "0" + (date.getMinutes());
- var seconds = (date.getSeconds()) > 9 ? (date.getSeconds()) : "0" + (date.getSeconds());
- dateString =
- hours + ":" +
- minutes + ":" +
- seconds;
- return dateString;
- }
-
- /**
- * 当车辆的温度值超过20时,更改小车颜色
- */
- function changeColor(obj) {
- var value = obj.getAttribute("monitorData/温度");
- if (value > 20) {
- obj.style.color = 'rgb(255,0,0)';
- } else {
- obj.style.color = null;
- }
- }
总结一下WebSocket最大的优点,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,真正实现了数据的实时双向通信。并且 WebSocket 通信不受同源策略的限制,不存在跨域问题。