当前位置: 首页 > article >正文

uniapp+vue3实现CK通信协议(基于jjc-tcpTools)

1. TCP 服务封装 (tcpService.js)

export class TcpService {constructor() {this.connections = uni.requireNativePlugin('jjc-tcpTools')this.clients = new Map() // 存储客户端连接this.servers = new Map() // 存储服务端实例}// 创建 TCP 服务端 (字符串模式)createStringServer(port, onCreated, onData, onConnect) {this.connections.createTcpServer(port,(res) => {console.log('Server created:', res)this.servers.set(port, { type: 'string' })onCreated?.(res)},(res) => {console.log('Received data:', res)this._addClient(res.ip, res.port)onData?.(res)},(res) => {console.log('New connection:', res)this._addClient(res.ip, res.port)onConnect?.(res)})}// 创建 TCP 服务端 (字节数组模式)createByteServer(port, onCreated, onData) {this.connections.createByteTcpServer(port,(res) => {console.log('Byte server created:', res)this.servers.set(port, { type: 'byte' })onCreated?.(res)},(res) => {console.log('Received byte data:', res)this._addClient(res.ip, res.port)onData?.(res)})}// 创建 TCP 客户端 (字符串模式)createStringClient(ip, port, onCreated, onData) {this.connections.createTcpClient(ip,port,(res) => {console.log('Client connected:', res)this.clients.set(`${ip}:${port}`, { type: 'string' })onCreated?.(res)},(res) => {console.log('Client received:', res)onData?.(res)})}// 创建 TCP 客户端 (字节数组模式)createByteClient(ip, port, onCreated, onData) {this.connections.createByteTcpClient(ip,port,(res) => {console.log('Byte client connected:', res)this.clients.set(`${ip}:${port}`, { type: 'byte' })onCreated?.(res)},(res) => {console.log('Byte client received:', res)onData?.(res)})}// 发送数据 (服务端群发字符串)sendToAllClients(port, message, callback) {this.connections.sendTcpMSG2Client(port,message,(res) => {console.log('Send to all:', res)callback?.(res)})}// 发送数据 (服务端指定客户端发字符串)sendToClients(port, clients, message, callback) {this.connections.sendTcpMSG2Clients(port,JSON.stringify(clients),message,(res) => {console.log('Send to clients:', res)callback?.(res)})}// 发送数据 (客户端发字符串)sendToServer(ip, port, message, callback) {this.connections.sendTcpMSG2Server(ip,port,message,(res) => {console.log('Send to server:', res)callback?.(res)})}// 发送字节数据 (服务端群发)sendBytesToAllClients(port, byteArray, callback) {this.connections.sendTcpByteMSG2Client(port,byteArray,(res) => {console.log('Send bytes to all:', res)callback?.(res)})}// 发送字节数据 (服务端指定客户端发)sendBytesToClients(port, clients, byteArray, callback) {this.connections.sendTcpByteMSG2Clients(port,JSON.stringify(clients),byteArray,(res) => {console.log('Send bytes to clients:', res)callback?.(res)})}// 发送字节数据 (客户端发)sendBytesToServer(ip, port, byteArray, callback) {this.connections.sendTcpMSGByte2Server(ip,port,byteArray,(res) => {console.log('Send bytes to server:', res)callback?.(res)})}// 设置客户端重连时间setReconnectTime(ip, port, interval, callback) {this.connections.setReConnectTime(ip,port,interval,(res) => {console.log('Set reconnect time:', res)callback?.(res)})}// 关闭客户端closeClient(ip, port, callback) {this.connections.closeTcpClient(ip,port,(res) => {console.log('Client closed:', res)this.clients.delete(`${ip}:${port}`)callback?.(res)})}// 关闭服务端closeServer(port, callback) {this.connections.closeTcpServer(port,(res) => {console.log('Server closed:', res)this.servers.delete(port)callback?.(res)})}// 私有方法:添加客户端记录_addClient(ip, port) {const key = `${ip}:${port}`if (!this.clients.has(key)) {this.clients.set(key, { ip, port })}}
}// 单例模式导出
export const tcpService = new TcpService()

2. CK协议适配器 (ckProtocol.js)

import { tcpService } from './tcpService'
import { crc16 } from './crc16'// 命令类型枚举
const CMD_TYPE = {LOCK_CONTROL: 0x01,// ...其他命令类型
}export class CKProtocol {constructor() {this.cabinetNo = 0 // 默认柜号this.serialNo = 0 // 序列号计数器}// 初始化连接init(ip, port = 5460) {this.serverIp = ipthis.serverPort = port// 创建字节数组模式的客户端连接tcpService.createByteClient(ip,port,(res) => {console.log('Connected to CK device:', res)this.isConnected = res.result === 'success'},(res) => {this.handleDeviceResponse(res)})}// 构建协议帧buildFrame(cmdType, cmdTag, data = null) {const magic = 0x1799 // 上位机→主板通信const dataLength = data ? data.length : 0const buffer = new ArrayBuffer(11 + dataLength)const view = new DataView(buffer)// 填充帧头view.setUint16(0, magic, false)view.setUint8(2, this.cabinetNo)view.setUint32(3, this.serialNo++, false)view.setUint8(7, cmdType)view.setUint8(8, cmdTag)view.setUint16(9, dataLength, false)// 填充数据区if (data && dataLength > 0) {for (let i = 0; i < dataLength; i++) {view.setUint8(11 + i, data[i])}}// 计算CRC16const crc = crc16(new Uint8Array(buffer.slice(0, 11 + dataLength)))// 创建最终字节数组const fullFrame = new Uint8Array(13 + dataLength)fullFrame.set(new Uint8Array(buffer), 0)fullFrame.set([crc >> 8, crc & 0xFF], 11 + dataLength)return fullFrame}// 发送命令sendCommand(cmdType, cmdTag, data = null) {if (!this.isConnected) {console.error('Not connected to device')return false}const frame = this.buildFrame(cmdType, cmdTag, data)tcpService.sendBytesToServer(this.serverIp,this.serverPort,Array.from(frame),(res) => {console.log('Command sent:', res)})return true}// 处理设备响应handleDeviceResponse(response) {try {// 将响应数据转换为Uint8Arrayconst data = new Uint8Array(response.msg.split(',').map(Number))// 解析响应帧if (data.length < 12) {throw new Error('Invalid response length')}const view = new DataView(data.buffer)const magic = view.getUint16(0, false)const cabinetNo = view.getUint8(2)const serialNo = view.getUint32(3, false)const cmdType = view.getUint8(7)const cmdTag = view.getUint8(8)const result = view.getUint8(9)const dataLength = view.getUint16(10, false)// 验证CRCconst receivedCrc = view.getUint16(12 + dataLength, false)const calculatedCrc = crc16(data.slice(0, 12 + dataLength))if (receivedCrc !== calculatedCrc) {throw new Error('CRC check failed')}// 提取数据区let responseData = nullif (dataLength > 0) {responseData = data.slice(12, 12 + dataLength)}// 返回解析结果return {magic,cabinetNo,serialNo,cmdType,cmdTag,result,dataLength,data: responseData}} catch (error) {console.error('Failed to parse device response:', error)return null}}// 锁控命令controlLock(lockNo, action) {const tagMap = {open: 0x01,close: 0x03,status: 0x02,openAll: 0x06}const tag = tagMap[action]if (tag === undefined) return falseconst data = action === 'openAll' ? null : new Uint8Array([lockNo])return this.sendCommand(CMD_TYPE.LOCK_CONTROL, tag, data)}// 查询设备信息queryDeviceInfo(infoType) {const tagMap = {mac: 0x01,hardwareVersion: 0x02,softwareVersion: 0x03,firmwareTime: 0x04,uptime: 0x05}const tag = tagMap[infoType]if (tag === undefined) return falsereturn this.sendCommand(CMD_TYPE.QUERY_INFO, tag)}// 其他协议命令...
}// 单例模式导出
export const ckProtocol = new CKProtocol()

3. Vue组件中使用 (DeviceControl.vue)

<template><view class="device-control"><view class="connection-section"><input v-model="serverIp" placeholder="设备IP" /><input v-model="serverPort" placeholder="端口号" type="number" /><button @click="connectDevice" :disabled="isConnected">连接</button><button @click="disconnectDevice" :disabled="!isConnected">断开</button></view><view class="command-section"><view class="command-group"><text class="group-title">锁控制</text><button @click="openLock(1)">开锁1</button><button @click="closeLock(1)">关锁1</button><button @click="openAllLocks">开所有锁</button></view><view class="command-group"><text class="group-title">设备查询</text><button @click="queryMac">查询MAC</button><button @click="queryVersion">查询版本</button></view></view><view class="log-section"><text class="section-title">通信日志</text><scroll-view class="log-content" scroll-y><view v-for="(log, index) in logs" :key="index" class="log-item">{{ log }}</view></scroll-view></view></view>
</template><script setup>
import { ref } from 'vue'
import { ckProtocol } from '@/api/ckProtocol'const serverIp = ref('192.168.1.100')
const serverPort = ref('5460')
const isConnected = ref(false)
const logs = ref([])// 连接设备
const connectDevice = () => {addLog(`正在连接 ${serverIp.value}:${serverPort.value}...`)ckProtocol.init(serverIp.value, parseInt(serverPort.value))// 模拟连接成功 (实际应该通过回调事件)setTimeout(() => {isConnected.value = trueaddLog('连接成功')}, 1000)
}// 断开连接
const disconnectDevice = () => {tcpService.closeClient(serverIp.value, serverPort.value, (res) => {isConnected.value = falseaddLog('已断开连接')})
}// 锁控制命令
const openLock = (lockNo) => {addLog(`发送开锁命令: 锁${lockNo}`)ckProtocol.controlLock(lockNo, 'open')
}const closeLock = (lockNo) => {addLog(`发送关锁命令: 锁${lockNo}`)ckProtocol.controlLock(lockNo, 'close')
}const openAllLocks = () => {addLog('发送开所有锁命令')ckProtocol.controlLock(null, 'openAll')
}// 查询命令
const queryMac = () => {addLog('发送查询MAC地址命令')ckProtocol.queryDeviceInfo('mac')
}const queryVersion = () => {addLog('发送查询版本命令')ckProtocol.queryDeviceInfo('softwareVersion')
}// 添加日志
const addLog = (message) => {const timestamp = new Date().toLocaleTimeString()logs.value.unshift(`[${timestamp}] ${message}`)if (logs.value.length > 100) {logs.value.pop()}
}
</script><style>
.device-control {padding: 20px;
}.connection-section {display: flex;flex-wrap: wrap;gap: 10px;margin-bottom: 20px;
}.connection-section input {flex: 1;min-width: 120px;padding: 8px;border: 1px solid #ddd;border-radius: 4px;
}.connection-section button {min-width: 80px;
}.command-section {margin-bottom: 20px;
}.command-group {margin-bottom: 15px;padding: 10px;background-color: #f5f5f5;border-radius: 8px;
}.group-title {display: block;font-weight: bold;margin-bottom: 8px;
}.command-group button {margin-right: 10px;margin-bottom: 8px;
}.log-section {margin-top: 20px;
}.section-title {font-weight: bold;margin-bottom: 8px;
}.log-content {height: 200px;padding: 10px;background-color: #f0f0f0;border-radius: 4px;font-family: monospace;font-size: 12px;
}.log-item {margin-bottom: 4px;padding-bottom: 4px;border-bottom: 1px solid #e0e0e0;
}
</style>

4. CRC16工具 (crc16.js)

// CRC-16/XMODEM (x16 + x12 + x5 + 1)
export function crc16(data) {let crc = 0x0000for (let i = 0; i < data.length; i++) {crc ^= data[i] << 8for (let j = 0; j < 8; j++) {if (crc & 0x8000) {crc = (crc << 1) ^ 0x1021} else {crc <<= 1}}}return crc & 0xFFFF
}

关键点说明

  1. 完全适配 jjc-tcpTools 插件

    • 严格按照插件提供的 API 进行封装
    • 支持字符串和字节数组两种通信模式
    • 实现了服务端和客户端的所有基本操作
  2. CK 协议实现

    • 按照文档规范构建协议帧
    • 实现了 CRC16 校验
    • 封装了常用命令如锁控制、设备查询等
  3. 组件集成

    • 提供直观的设备控制界面
    • 显示通信日志
    • 管理连接状态
  4. 错误处理

    • 基本的错误检测和日志记录
    • CRC 校验确保数据完整性
  5. 扩展性

    • 可以轻松添加更多协议命令
    • 支持多设备管理

相关文章:

uniapp+vue3实现CK通信协议(基于jjc-tcpTools)

1. TCP 服务封装 (tcpService.js) export class TcpService {constructor() {this.connections uni.requireNativePlugin(jjc-tcpTools)this.clients new Map() // 存储客户端连接this.servers new Map() // 存储服务端实例}// 创建 TCP 服务端 (字符串模式)createStringSe…...

Python爬虫实战:研究urlparse库相关技术

1 引言 1.1 研究背景与意义 网络爬虫作为互联网数据采集的核心技术,在信息检索、舆情分析、数据挖掘等领域具有广泛应用。随着 Web 技术的发展,现代网站 URL 结构日益复杂,包含路径参数、查询参数、锚点等多种组件,且存在相对路径、URL 编码等问题,给爬虫开发带来了挑战…...

解锁FastAPI与MongoDB聚合管道的性能奥秘

title: 解锁FastAPI与MongoDB聚合管道的性能奥秘 date: 2025/05/20 20:24:47 updated: 2025/05/20 20:24:47 author: cmdragon excerpt: MongoDB聚合管道是一种分阶段处理数据的流水线&#xff0c;通过$match、$group等阶段对文档进行特定操作&#xff0c;具有内存优化和原生操…...

软件工程方法论:在确定性与不确定性的永恒之舞中寻找平衡

更多精彩请访问&#xff1a;通义灵码2.5——基于编程智能体开发Wiki多功能搜索引擎-CSDN博客 当我们谈论“软件工程”时&#xff0c;“工程”二字总暗示着某种如桥梁建造般的精确与可控。然而&#xff0c;软件的本质却根植于人类思维的复杂性与需求的流变之中。软件工程方法论的…...

Unity中的MonoSingleton<T>与Singleton<T>

1.MonoSingleton 代码部分 using UnityEngine;/// <summary> /// MonoBehaviour单例基类 /// 需要挂载到GameObject上使用 /// </summary> public class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T> {private static T _instance;…...

怎么通过 jvmti 去 hook java 层函数

使用 JVMTI 手动实现 Android Java 函数 Hook 要通过 JVMTI 手动实现 Android Java 函数 Hook&#xff0c;需要编写 Native 层代码并注入到目标进程中。以下是详细步骤和示例&#xff1a; 一、核心实现原理 JVMTI 提供两种主要 Hook 方式&#xff1a; Method Entry/Exit 事…...

兰亭妙微 | 医疗软件的界面设计能有多专业?

从医疗影像系统到手术机器人控制界面&#xff0c;从便携式病原体检测设备到多平台协同操作系统&#xff0c;兰亭妙微为众多医疗设备研发企业&#xff0c;打造了兼具专业性与可用性的交互界面方案。 我们不仅做设计&#xff0c;更深入理解医疗场景的实际需求&#xff1a; 对精…...

前端原生构建交互式进度步骤组件(Progress Steps)

在现代网页设计中&#xff0c;进度步骤&#xff08;Progress Steps&#xff09; 是一种常见的 UI 模式&#xff0c;常用于引导用户完成注册流程、多步表单、教程或任何需要分步骤操作的场景。本文将带你从零开始构建一个美观且功能完整的 “进度步骤”组件&#xff0c;并详细讲…...

如何给windos11 扩大C盘容量

动不动C盘就慢了&#xff0c;苹果逼着用户换手机&#xff0c;三天两头更新系统&#xff0c;微软也是毫不手软。c盘 从10个G就够用&#xff0c;到100G 也不够&#xff0c;看来通货膨胀是部分行业的。 在 Windows 11 中扩大 C 盘容量&#xff0c;主要取决于磁盘分区布局和可用空…...

【基于阿里云搭建数据仓库(离线)】Data Studio创建资源与函数

Data Studio支持在您的数据分析代码中引用自定义的资源和函数&#xff08;支持MaxCompute、EMR、CDH、Flink&#xff09;&#xff0c;您需要先创建或上传资源、函数至目标工作空间&#xff0c;上传后才可在该工作空间的任务中使用。您可参考本文了解如何使用DataWorks可视化方式…...

Linux_T(Sticky Bit)粘滞位详解

Linux 粘滞位&#xff08;Sticky Bit&#xff09;详解 一、什么是粘滞位&#xff08;Sticky Bit&#xff09; 粘滞位&#xff08;Sticky Bit&#xff09;是 Linux 和 Unix 系统中一种特殊的权限设置&#xff0c;主要应用于目录&#xff0c;其作用是在多人共享访问的目录中&am…...

web3-以太坊智能合约基础(理解智能合约Solidity)

以太坊智能合约基础&#xff08;理解智能合约/Solidity&#xff09; 无需编程经验&#xff0c;也可以帮助你了解Solidity独特的部分&#xff1b;如果本身就有相应的编程经验如java&#xff0c;python等那么学起来也会非常的轻松 一、Solidity和EVM字节码 实际上以太坊链上储存…...

高敏感应用如何保护自身不被逆向?iOS 安全加固策略与工具组合实战(含 Ipa Guard 等)

如果你正在开发一款涉及支付、隐私数据或企业内部使用的 App&#xff0c;那么你可能比多数开发者更早意识到一件事——App 一旦被破解&#xff0c;损失的不只是代码&#xff0c;还有信任与业务逻辑。 在我们为金融类工具、HR 系统 App、数据同步组件等高敏感项目提供支持的过程…...

【C++项目】负载均衡在线OJ系统-2

文章目录 oj_server模块编写oj_server框架的搭建-oj_server/oj_server.cpp 路由框架 oj_model模块编写题目信息设置v1.文件版本-common/util.hpp boost库spilt函数的使用-oj_server/oj_model_file.hpp 文件版本model编写v2.mysql数据库版本1.mysql创建授权用户、建库建表录入操…...

GC1809:高性能24bit/192kHz音频接收芯片解析

1. 芯片概述 GC1809 是数字音频接收芯片&#xff0c;支持IEC60958、S/PDIF、AES3等协议&#xff0c;集成8选1输入切换、低抖动时钟恢复和24bit DAC&#xff0c;适用于家庭影院、汽车音响等高保真场景。 核心特性 高精度&#xff1a;24bit分辨率&#xff0c;动态范围105dB&…...

2025年06月05日Github流行趋势

项目名称&#xff1a;onlook 项目地址url&#xff1a;https://github.com/onlook-dev/onlook项目语言&#xff1a;TypeScript历史star数&#xff1a;16165今日star数&#xff1a;1757项目维护者&#xff1a;Kitenite, drfarrell, spartan-vutrannguyen, apps/devin-ai-integrat…...

flask功能使用总结和完整示例

Flask 功能使用总结与完整示例 一、Flask 核心功能总结 Flask 是轻量级 Web 框架&#xff0c;核心功能包括&#xff1a; 路由系统&#xff1a;通过 app.route 装饰器定义 URL 与函数的映射。模板引擎&#xff1a;默认使用 Jinja2&#xff0c;支持动态渲染 HTML。请求处理&…...

AWS 亚马逊 S3存储桶直传 前端demo 复制即可使用

自己踩过坑不想别人也踩坑了 亚马逊S3存储桶直传前端demo复制即可使用 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0…...

DAY 15 复习日

浙大疏锦行 数据使用爬虫爬取weibo数据&#xff0c;下面是代码 import datetime import os import csv import timeimport numpy as np import random import re import urllib.parse import requests from fake_useragent import UserAgentdef init():if not os.path.exists…...

Vue Router 导航方法完全指南

&#x1f4d6; 前言 在 Vue 项目中&#xff0c;我们经常需要在不同页面之间跳转&#xff0c;或者更新当前页面的 URL 参数。Vue Router 提供了几种不同的导航方法&#xff0c;每种方法都有其特定的使用场景。本文将详细讲解这些方法的区别和最佳实践。 &#x1f3af; 核心概念…...

MidJourney入门学习

1. 引言 MidJourney 是一款由美国科技公司开发的先进文本到图像生成 AI 工具,自 2022 年推出以来迅速在创意产业和社交媒体领域引发轰动。与 Stable Diffusion 不同,MidJourney 以其独特的美学风格、高度细节化的图像生成能力和强大的创意引导功能著称,成为设计师、艺术家和…...

2025最新Java日志框架深度解析:Log4j 2 vs Logback性能实测+企业级实战案例

一、为什么printStackTrace是"代码坟场"&#xff1f; 你写的日志可能正在拖垮系统&#xff01; 在Java开发中&#xff0c;直接调用printStackTrace()打印异常堆栈是最常见的"自杀式操作"。这种方式会导致三大致命问题&#xff1a; 无法分级控制&#xff…...

如何安全高效的文件管理?文件管理方法

文件的管理早已不只是办公场景中的需求。日常生活、在线学习以及个人收藏中&#xff0c;文件管理正逐渐成为我们数字生活中的基础。但与此同时&#xff0c;文件管理的混乱、低效以及安全性问题也频繁困扰着许多人。 文件管理的挑战与解决思路 挑战一&#xff1a;文件存储无序…...

基于BI PaaS架构的衡石HENGSHI SENSE平台技术解析:重塑企业级数据分析基座

在数据驱动决策的时代&#xff0c;传统BI工具日益显露出扩展性弱、灵活性差、资源利用率低等痛点。衡石科技推出的HENGSHI SENSE平台&#xff0c;创新性地采用BI PaaS&#xff08;平台即服务&#xff09;架构&#xff0c;为企业构建了一个强大、开放、可扩展的数据分析基础设施…...

Hive中ORC存储格式的优化方法

优化Hive中的ORC(Optimized Row Columnar)存储格式可显著提升查询性能、降低存储成本。以下是详细的优化方法,涵盖参数配置、数据组织、写入优化及监控调优等维度: 一、ORC核心参数优化 1. 存储与压缩参数 SET orc.block.size=268435456; -- 块大小(默认256MB)…...

代码训练LeetCode(23)随机访问元素

代码训练(23)LeetCode之随机访问元素 Author: Once Day Date: 2025年6月5日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 380. O(1) 时间插入、删除和获取随机元素 - 力扣&#xff08;LeetCode&#xff09;力…...

【R语言编程绘图-plotly】

安装与加载 在R中使用plotly库前需要安装并加载。安装可以通过CRAN进行&#xff0c;使用install.packages()函数。加载库使用library()函数。 install.packages("plotly") library(plotly)测试库文件安装情况 # 安装并加载必要的包 if (!requireNamespace("p…...

float、double 这类 浮点数 相比,DECIMAL 是另一种完全不同的数值类型

和 float、double 这类**“浮点数”**相比&#xff0c;DECIMAL 是另一种完全不同的数值类型&#xff0c;叫做&#xff1a; ✅ DECIMAL 是什么&#xff1f; DECIMAL 是“定点数”类型&#xff08;fixed-point&#xff09;&#xff0c;用于存储精确的小数值&#xff0c;比如&…...

通信刚需,AI联手ethernet/ip转profinet网关打通工业技术难关

工业人工智能&#xff1a;食品和饮料制造商的实际用例通信刚需 了解食品饮料制造商如何利用人工智能克服业务挑战 食品和饮料制造商正面临劳动力短缺、需求快速变化、运营复杂性加剧以及通胀压力等挑战。如今&#xff0c;生产商比以往任何时候都更需要以更少的投入实现更高的…...

JavaEE->多线程:定时器

定时器 约定一个时间&#xff0c;时间到了&#xff0c;执行某个代码逻辑&#xff08;进行网络通信时常见&#xff09; 客户端给服务器发送请求 之后就需要等待 服务器的响应&#xff0c;客户端不可能无限的等&#xff0c;需要一个最大的期限。这里“等待的最大时间”可以用定时…...