实习日志30

概要

高拍仪硬件通信原理,WebSocket源码解析(JavaScript)

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

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

现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

ps:本来想写sm4加密和解密算法的,但是sm3一个加密都看的我头昏昏的,就先不为难自己了,说说WebSocket的源码解析吧

源自: HTML5 WebSocket | 菜鸟教程 (runoob.com)

整体架构流程

拟人化展示从HTTP协议升级到WebSocket协议的过程:

1、发送一个GET请求
关键: Upgrade: websocket; Connection: Upgrade;
这两个就告诉服务器,我要发起websocket协议,我不是HTTP。

2、服务器收到了协议,返回一个 Switching Protocol, 这样就连接成功了。

3、接下来的通信都是websocket, 这样就很好的连接了。

源自:WebSocket建立连接的过程_websocket如何建立连接-CSDN博客

 

技术名词解释

连接请求:Connection: Upgrade;

通信消息数据:(二进制消息)

技术细节

一、建立连接:

在高拍仪初始化时建立连接

初始化,设置显示相机屏幕大小,设置自动裁剪(初始化后才能设置)

function LoadCameraDocument() {

    if (!window.WebSocket) {
        alert("浏览器不支持HTML5,请更新浏览器或者使用其它浏览器");
    }
    //console.log("LoadCameraDocument");
    var obj = document.getElementById("CameraCtl");
    Cam_ControlInit(obj, 0, 0, 600, 400);
    // 模拟异步硬件初始化
    setTimeout(function () {
        // 设置自动裁剪
        SetCameraCutMode();
    }, 2500); // 假设2.5秒后硬件初始化完成
    // 模拟异步硬件初始化
    setTimeout(function () {
        // 设置自动裁剪
        SetCameraCutMode();
    }, 5000); // 完不成再来一下
}

 连接WebSocket,初始化相机

//*************摄像头操作初始化***************
function Cam_ControlInit(documentObj, mX, mY, mwidth, mheight) {
    WebSocketConnect();
    InitCanvas(documentObj, mX, mY, mwidth, mheight);
    //console.log("Cam_ControlInit");
}

 设置连接地址和开启时函数,

        设置心跳检测、断线重连、获取设备数目

        完成后输出连接成功 "socket.onopen"

socket = new WebSocket("ws://127.0.0.1:22225");
socket.binaryType = "arraybuffer";

socket.onopen = function (event) {

            //heartCheck.reset().start(); 
            heartCheck();
            isSocketConnect = true;
            clearInterval(intervalId);
            //if (isOpenMainCamera == false)         
            Cam_GetDevCount();
            console.log("socket.onopen");

        };

二、发送数据:

首先要有心跳,if (isSocketConnect)

其次,创建二进制数组 var aDataArray = new Uint8Array(totalLen)

然后,消息分装

最后,发送二进制消息 socket.send(aDataArray.buffer);

示例“处理拍照逻辑发送消息逻辑”代码:


function CaptureImage(fileAddr) {

    if (isSocketConnect) {

        // var pathArray = stringToUint8Array(fileAddr);
        if (fileAddr == "") {
            var packageCount = 1;
            var len = 0;
            var pindex = 0;
            var totalLen = 12;
            var aDataArray = new Uint8Array(totalLen);
            aDataArray[0] = 0x77;
            aDataArray[1] = 0x88;
            aDataArray[2] = 0x10;
            aDataArray[3] = 0x00;
            aDataArray[4] = len >> 16 & 0xff;
            aDataArray[5] = len >> 8 & 0xff;
            aDataArray[6] = len & 0xff;
            aDataArray[7] = packageCount >> 8 & 0xff;   //包总数
            aDataArray[8] = packageCount & 0xff;   //包总数
            aDataArray[9] = 0;   //分包长度
            aDataArray[10] = pindex >> 8 & 0xff;   //包序号
            aDataArray[11] = pindex & 0xff;    //包序号
            console.log("pindex:" + pindex);
            socket.send(aDataArray.buffer);
        } else {
            var path = encodeURI(fileAddr);
            //console.log(path);
            var pathArray = stringToByte(path);
            var len = pathArray.length;

            var packageCount = 0;
            var tmpLen = len;
            while (tmpLen > 0) {
                tmpLen = tmpLen - 90;
                packageCount++;
            }

            console.log("packageCount:" + packageCount);

            var pindex = 0;
            tmpLen = len;
            while (tmpLen > 0) {
                tmpLen = tmpLen - 90;

                if (tmpLen > 0) {
                    var totalLen = 90 + 12;
                    var aDataArray = new Uint8Array(totalLen);
                    aDataArray[0] = 0x77;
                    aDataArray[1] = 0x88;
                    aDataArray[2] = 0x10;
                    aDataArray[3] = 0x00;
                    aDataArray[4] = len >> 16 & 0xff;
                    aDataArray[5] = len >> 8 & 0xff;
                    aDataArray[6] = len & 0xff;
                    aDataArray[7] = packageCount >> 8 & 0xff;   //包总数
                    aDataArray[8] = packageCount & 0xff;   //包总数
                    aDataArray[9] = 90;   //分包长度
                    aDataArray[10] = pindex >> 8 & 0xff;   //包序号
                    aDataArray[11] = pindex & 0xff;    //包序号
                    console.log("pindex:" + pindex);
                    for (var i = 0; i < 90; i++) {
                        aDataArray[12 + i] = pathArray[i + pindex * 90];
                    }
                    socket.send(aDataArray.buffer);
                } else {
                    var totalLen = 90 + tmpLen + 12;  // 此时tmpLen为负数,做加法运算
                    var aDataArray = new Uint8Array(totalLen);
                    aDataArray[0] = 0x77;
                    aDataArray[1] = 0x88;
                    aDataArray[2] = 0x10;
                    aDataArray[3] = 0x00;
                    aDataArray[4] = len >> 16 & 0xff;
                    aDataArray[5] = len >> 8 & 0xff;
                    aDataArray[6] = len & 0xff;
                    aDataArray[7] = packageCount >> 8 & 0xff;   //包总数
                    aDataArray[8] = packageCount & 0xff;   //包总数
                    aDataArray[9] = 90 + tmpLen;   //分包长度
                    aDataArray[10] = pindex >> 8 & 0xff;   //包序号
                    aDataArray[11] = pindex & 0xff;    //包序号
                    console.log("pindex:" + pindex);
                    for (var i = 0; i < (90 + tmpLen); i++) {
                        aDataArray[12 + i] = pathArray[i + pindex * 90];
                    }
                    socket.send(aDataArray.buffer);
                }
                pindex++;
                toSleep(80);
            }
        }

    }
}

三、响应数据:

例如:拍照时数据处理

创建onmessage方法,心跳检测必写

socket.onmessage = function (event) {

            // heartCheck.reset().start();      

            var rDataArr = new Uint8Array(event.data);
            if (rDataArr.length > 0) {
                // WebSocket心跳检测
                if (rDataArr[0] == 0x11 && rDataArr[1] == 0x11 && rDataArr[2] == 0x11) {
                    console.log("socket心跳 ❤");
                }
                // 处理rDataArr数据
                // 省略...示例代码
            }


}

响应数据方法:socket.onmessage = function (event) {}

示例"处理拍照结果返回响应逻辑"代码:

//拍照结果返回
if (rDataArr[2] == 0x10) {

    var flag;
    if (rDataArr[3] == 0x01) {
        flag = 0;
        var imgpathLen = rDataArr[4] * 256 + rDataArr[5];
        if (imgpathLen == 0) {
            var base64Len = rDataArr[6] * 65536 + rDataArr[7] * 256 + rDataArr[8];
            var imgPathStr = "";
            var base64Data = new Uint8Array(base64Len);
            for (var i = 0; i < base64Len; i++) {
                base64Data[i] = rDataArr[9 + imgpathLen + i];
            }
            var base64Str = Uint8ArrayToString(base64Data);
            GetCaptrueImgResultCB(flag, imgPathStr, base64Str);
        } else {
            var base64Len = rDataArr[6] * 65536 + rDataArr[7] * 256 + rDataArr[8];
            var pData = new Uint8Array(imgpathLen);
            for (var i = 0; i < imgpathLen; i++) {
                pData[i] = rDataArr[9 + i];
            }
            var str = byteToString(pData);
            var imgPathStr = decodeURIComponent(str);

            var base64Data = new Uint8Array(base64Len);
            for (var i = 0; i < base64Len; i++) {
                base64Data[i] = rDataArr[9 + imgpathLen + i];
            }
            var base64Str = Uint8ArrayToString(base64Data);

            GetCaptrueImgResultCB(flag, imgPathStr, base64Str);
        }
    }
    if (rDataArr[3] == 0x02) {
        flag = 2;
        GetCaptrueImgResultCB(flag, "", "");
    }

}

小结

WebSocket是一种在Web浏览器和服务器之间进行全双工通信的协议,通过它可以实现实时的数据传输。建立WebSocket连接的过程包括发送一个GET请求并指定协议升级,服务器返回一个Switching Protocol响应,连接成功后即可进行WebSocket通信。在实际应用中,可以通过WebSocket发送和接收二进制消息来实现各种功能,例如拍照、传输文件等。需要注意的是,为了保持连接的稳定性,通常会实现心跳检测和断线重连功能。

  1. 深入理解WebSocket协议:通过实际编码,我更深入地理解了WebSocket协议的工作原理和建立连接的过程。

  2. 网络通信能力提升:通过处理WebSocket通信的逻辑,我提升了自己的网络通信能力,包括发送和接收数据的处理能力。

  3. 异步编程理解:WebSocket通信通常是异步的,我巩固了如何处理异步通信,例如通过回调函数处理接收到的消息。

  4. 实践经验:通过实际编写WebSocket通信相关的代码,我积累了宝贵的实践经验,可以帮助我更好地理解和应用相关知识。

  5. 问题解决能力:在编写过程中可能遇到了各种问题,通过解决这些问题,我提升了自己的问题解决能力和调试技巧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/406461.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

07 MyBatis之高级映射 + 懒加载(延迟加载)+缓存

1. 高级映射 例如有两张表, 分别为班级表和学生表 自然, 一个班级对应多个学生 像这种数据 , 应该如果如何映射到Java的实体类上呢? 这就是高级映射解决的问题 以班级和学生为例子 , 因为一个班级对应多个学生 , 因此学生表中必定有一个班级编号字段cid 但我们在学生的实体…

5G网络(接入网+承载网+核心网)

5G网络&#xff08;接入网承载网核心网&#xff09; 一、5G网络全网架构图 这张图分为左右两部分&#xff0c;右边为无线侧网络架构&#xff0c;左边为固定侧网络架构。 无线侧&#xff1a;手机或者集团客户通过基站接入到无线接入网&#xff0c;在接入网侧可以通过RTN或者IP…

【BUG】解决java.util.Date and java.lang.String

报错解析与解决方案&#xff1a;Java中处理Date类型与String比较引发的IllegalArgumentException 前言 在日常的开发过程中&#xff0c;我们可能会遇到各种类型转换和比较相关的异常。今天&#xff0c;我在调用接口时就遭遇了这样一个问题&#xff1a; 错误描述 在执行SQL查…

unity ui界面优化

优化一个比较复杂的界面&#xff0c;里面有多个rt和组件。 在初次打开这个界面的时候会发生1s多的卡顿&#xff0c;还是非常严重的。 分析 通过profiler分析 1.打开界面时卡顿。 分析&#xff1a;除了update和dotween相关逻辑&#xff0c;主要在于打开时的lua function调用…

《隐私计算简易速速上手小册》第7章:隐私计算与云计算/边缘计算(2024 最新版)

文章目录 7.1 云计算中的隐私保护7.1.1 基础知识7.1.2 主要案例&#xff1a;使用 Python 实现云数据的安全上传和访问7.1.3 拓展案例 1&#xff1a;实现基于角色的访问控制7.1.4 拓展案例 2&#xff1a;使用 Python 保护 API 安全 7.2 边缘计算的隐私问题7.2.1 基础知识7.2.2 主…

RisingWave最佳实践-利用Dynamic filters 和 Temporal filters 实现监控告警

心得的体会 刚过了年刚开工&#xff0c;闲暇之余调研了分布式SQL流处理数据库–RisingWave&#xff0c;本人是Flink&#xff08;包括FlinkSQL和Flink DataStream API&#xff09;的资深用户&#xff0c;但接触到RisingWave令我眼前一亮&#xff0c;并且拿我们生产上的监控告警…

面试经典150题 -- 二叉树搜索树 (总结)

总的链接 : https://leetcode.cn/studyplan/top-interview-150/ 二叉搜索树相关概念 : 二叉搜索树是一个有序树。 若它的左子树不空&#xff0c;则左子树上所有结点的值均小于它的根结点的值&#xff1b;若它的右子树不空&#xff0c;则右子树上所有结点的值均大于它的根结…

PyTorch概述(六)---View

Tensor.view(*shape)-->Tensor 返回一个新的张量同之前的张量具有相同的数据&#xff0c;但是具有不同的形状&#xff1b;返回的张量同之前的张量共享相同的数据&#xff0c;必须具有相同数目的元素&#xff0c;可能具有不同的形状&#xff1b;对于经过view操作的张量&…

【Java程序设计】【C00286】基于Springboot的生鲜交易系统(有论文)

基于Springboot的生鲜交易系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的生鲜交易系统 本系统分为系统功能模块、管理员功能模块、用户功能模块以及商家功能模块。 系统功能模块&#xff1a;在系统首页可以…

[HTML]Web前端开发技术28(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

Linux-基础知识(黑马学习笔记)

硬件和软件 我们所熟知的计算机是由&#xff1a;硬件和软件组成。 硬件&#xff1a;计算机系统中电子&#xff0c;机械和光电元件等组成的各种物理装置的总称。 软件&#xff1a;是用户和计算机硬件之间的接口和桥梁&#xff0c;用户通过软件与计算机进行交流。 而操作系统…

【前端素材】推荐优质后台管理系统PORTAL平台模板(附源码)

一、需求分析 后台管理系统是一种具有多层次结构的软件系统&#xff0c;用于管理网站、应用程序或系统的后台操作和管理。下面是对后台管理系统的分层次、详细分析&#xff1a; 第一层&#xff1a;用户界面层 登录界面&#xff1a;提供用户登录验证&#xff0c;确保只有经过授…

村镇医院医疗中心污废水如何处理达标

污废水处理是村镇医院医疗中心运营中不可忽视的重要环节。如何有效处理污废水&#xff0c;使其达到相关标准&#xff0c;是保障医疗中心环境卫生的关键之一。 首先&#xff0c;村镇医院医疗中心应建立科学的废水处理系统。该系统应包括预处理、初级处理、中级处理和高级处理等环…

二十七、图像的均值模糊操作

项目功能实现&#xff1a;对一张图片进行均值模糊操作 按照之前的博文结构来&#xff0c;这里就不在赘述了 更多的图像模糊操作原理可参考博文&#xff1a;七、模糊操作&#xff0c;里面有详细原理讲解&#xff0c;只不过代码是python写的。 一、头文件 blurtest.h #pragma…

网络存储技术

第4章 存储文件系统 1.元数据 文件系统中的数据分为数据和元数据&#xff0c;数据是指普通文件中的实际数据&#xff0c;而元数据是描述数据属性的信息。 在Linux操作系统下&#xff0c;使用文件状态信息stat命令&#xff0c;可以显示文件的元数据如下。 [rootgitlab ~]# s…

英国客户亲临育菁,考察桌面级CNC机床

育菁桌面级CNC机床生产车间 2024年2月22日&#xff0c;英国某机床服务公司Alston和Gary一行拜访考察育菁&#xff0c;在育菁总经理Jimyang和总工程师Alan及海外营销中心总监Akuma的陪同下&#xff0c;参观了育菁桌面小型数控机床生产装配车间&#xff0c;并对育菁牌桌面型数控机…

《TCP/IP详解 卷一》第2章 Internet地址结构

目录 2.1 引言 2.2 表示IP地址 2.3 基本的IP地址结构 单播地址 全球单播地址&#xff1a; 组播地址 任播地址 2.4 CIDR和聚合 2.5 特殊用途地址 2.6 分配机构 2.7 单播地址分配 2.8 与IP地址相关的攻击 2.9 总结 2.1 引言 2.2 表示IP地址 IPv4地址&#xff1a;3…

【寸铁的刷题笔记】树、dfs、bfs、回溯、递归(二)

【寸铁的刷题笔记】树、dfs、bfs、回溯、递归(二) 大家好 我是寸铁&#x1f44a; 金三银四&#xff0c;树、dfs、bfs、回溯、递归是必考的知识点✨ 快跟着寸铁刷起来&#xff01;面试顺利上岸&#x1f44b; 喜欢的小伙伴可以点点关注 &#x1f49d; 上期回顾 感谢大家的支持&am…

Matlab/simulink基于vsg的风光储调频系统建模仿真(持续更新)

​ 1.Matlab/simulink基于vsg的风光储调频系统建模仿真&#xff08;持续更新&#xff09;

LeetCode 2583.二叉树中的第 K 大层和:层序遍历 + 排序

【LetMeFly】2583.二叉树中的第 K 大层和&#xff1a;层序遍历 排序 力扣题目链接&#xff1a;https://leetcode.cn/problems/kth-largest-sum-in-a-binary-tree/ 给你一棵二叉树的根节点 root 和一个正整数 k 。 树中的 层和 是指 同一层 上节点值的总和。 返回树中第 k …