#星光不负 码向未来# HarmonyOS开发实战:串行通信全流程解析 原创
引言
在全场景智慧生态中,设备间的数据互联互通是实现“万物互联”的核心基石,而串行通信作为一种经典且可靠的数据传输技术,凭借其硬件依赖低、传输稳定、适配性广的优势,成为HarmonyOS连接嵌入式设备、外设模块的关键桥梁,从智能家电的控制面板与核心模块通信,到工业设备的数据采集,再到蓝牙外设(如打印机、传感器)的指令交互,串行通信技术贯穿于多类HarmonyOS应用的底层数据传输环节;同时,HarmonyOS为开发者提供了一套标准化、高兼容性的串行通信开发框架,不仅封装了复杂的硬件驱动逻辑与协议解析过程,还通过清晰的API设计,让开发者无需深入底层细节,就能快速实现设备配置、数据收发、错误处理等核心功能,当前随着物联网与智能硬件市场的爆发,HarmonyOS设备的应用场景持续拓展,对串行通信的需求也从基础的数据传输,升级为“低延迟、高可靠、可扩展”的综合需求。那么本文将以“理论+实战”为核心,从串行通信的基础概念入手,梳理HarmonyOS串行通信的核心组件与关键参数。

关于串行通信
先来介绍一下串行通信,串行通信是指数据以“位”为单位,按顺序逐位在单条传输线路上传输的通信方式,与并行通信(多线路同时传输多位数据)相比,它具有硬件成本低、传输距离远、抗干扰能力强的特点,广泛应用于嵌入式系统、外部设备(如蓝牙模块、传感器、打印机)的数据交换场景。在HarmonyOS的串行通信开发中,需重点关注SPP(Serial Port Profile,串口协议)这是一种基于蓝牙的标准化协议,可将蓝牙设备模拟为“虚拟串口”,让设备间通过蓝牙实现类似传统串口的双向数据传输,支持文件、文本、指令等各类数据格式的传递。HarmonyOS串行通信涉及以下5个核心基础概念,是配置设备与实现通信的关键:
- 串行端口(Serial Port):物理层面的通信接口,是设备间建立连接的硬件基础,用于传输数据信号与控制信号。
- 波特率(Baud Rate):单位时间内传输的“码元数”,是衡量数据传输速率的核心指标,常见取值为9600bps、115200bps,需确保通信双方的波特率一致,否则会导致数据解析错误。
- 数据位(Data Bits):每个“字节数据”包含的有效数据位数,常见取值为7位或8位,通常默认使用8位(可覆盖大部分ASCII字符编码需求)。
- 停止位(Stop Bits):用于标识一个字节数据传输结束的信号位,常见取值为1位、1.5位或2位,主要作用是避免数据传输的连续性导致接收端误判。
- 奇偶校验(Parity):一种简单的错误检测机制,通过在数据位后添加1位校验位,使“数据位+校验位”的总位数满足奇数(奇校验)或偶数(偶校验)规则,帮助接收端判断数据是否在传输中丢失或出错。
使用场景
HarmonyOS提供的串行通信API,围绕“设备互联与数据交互”设计,可满足多类场景的开发需求,其中最核心、最常用的两大场景如下:
- 服务端向客户端写入数据:适用于“一对一”的主从通信架构,例如HarmonyOS设备作为服务端(主设备),外接传感器模块作为客户端(从设备),服务端需向客户端发送配置指令(如采样频率、数据格式),或接收客户端上传的采集数据。
- 通过socket连接对端设备:适用于跨设备的蓝牙互联场景,例如两台HarmonyOS设备(如手机与智能手表),或HarmonyOS设备与第三方蓝牙外设(如蓝牙打印机),通过socket建立稳定连接后,实现双向数据传输(如发送打印指令、接收打印状态)。
接下来将针对上述两大核心场景,详细拆解开发流程,并提供可直接复用的源码示例,确保开发者能“按步骤落地”。
1、服务端向客户端写入数据
该场景的核心是“HarmonyOS设备作为服务端,创建socket监听并等待客户端连接,连接成功后向客户端发送数据,同时可订阅客户端回传的数据”,具体开发流程与源码如下:
(1)开发流程
1. 导入串行通信所需的socket模块,提供核心API支持。
2. 声明依赖的系统能力SystemCapability.Communication.Bluetooth.Core,确保应用有权限访问蓝牙与串行通信功能。
3. 开启设备蓝牙,这是建立串行通信连接的前提(需引导用户授权开启)。
4. 创建服务端socket,通过配置参数生成唯一的serverId,用于标识服务端连接。
5. 服务端进入“等待连接”状态,客户端发起连接后,返回唯一的clientId,标识当前客户端连接。
6. 服务端通过clientId,向对应的客户端写入数据(如配置指令、文本信息)。
7. (可选)服务端订阅“客户端写入数据”事件,实时接收客户端回传的数据(如状态反馈、采集结果)。
8. 通信结束后,注销服务端socket,释放serverId对应的资源。
9. 注销客户端socket,释放clientId对应的资源,避免内存泄漏。
(2)源码示例
// 导入串行通信所需模块:socket模块用于通信,AsyncCallback/BusinessError用于异步回调与错误处理
import { socket } from '@kit.ConnectivityKit';
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
// 1. 创建服务端监听Socket,生成唯一serverId(用于标识服务端)
let serverNumber = -1; // 初始化serverId为-1,标识未创建成功
// 配置SPP参数:uuid为标准串口协议UUID,secure表示是否加密,type为连接类型(0为默认)
let sppOption: socket.SppOptions = {
uuid: '00001101-0000-1000-8000-00805f9b34fb', // 通用SPP协议UUID,多数蓝牙外设支持
secure: true, // 开启加密传输,保障数据安全
type: 0 // 连接类型:0为RFCOMM类型(经典蓝牙常用)
};
// 调用sppListen创建服务端,异步回调返回结果
socket.sppListen('server1', sppOption, (code, serverSocketID) => {
if (code != null) {
// 若code不为null,说明创建失败(如权限不足、蓝牙未开启),可在此处添加错误处理逻辑
console.error('创建服务端socket失败,错误码:', code);
return;
} else {
// 创建成功,将返回的serverSocketID赋值给serverNumber,用于后续操作
serverNumber = serverSocketID;
console.log('服务端socket创建成功,serverId:', serverNumber);
}
});
// 2. 服务端等待客户端连接,连接成功后返回clientId(用于标识客户端)
let clientNumber = -1; // 初始化clientId为-1,标识未连接成功
// 调用sppAccept等待连接,传入serverNumber指定服务端
socket.sppAccept(serverNumber, (code, clientSocketID) => {
if (code != null) {
// 连接失败(如客户端超时、设备离线),添加错误处理逻辑
console.error('客户端连接失败,错误码:', code);
return;
} else {
// 连接成功,将返回的clientSocketID赋值给clientNumber
clientNumber = clientSocketID;
console.log('客户端连接成功,clientId:', clientNumber);
}
});
// 3. 服务端向客户端写入数据(示例:写入"A""B""C""D"四个字符)
// 创建Uint8Array数组存储数据(串行通信常用二进制格式传输)
let array = new Uint8Array(990); // 初始化数组长度为990,可根据实际数据长度调整
array[0] = 'A'.charCodeAt(0); // 将字符"A"转为ASCII码,存入数组第0位
array[1] = 'B'.charCodeAt(0); // 字符"B"存入第1位
array[2] = 'C'.charCodeAt(0); // 字符"C"存入第2位
array[3] = 'D'.charCodeAt(0); // 字符"D"存入第3位
// 调用sppWrite写入数据,传入clientNumber指定客户端,array.buffer为二进制数据
socket.sppWrite(clientNumber, array.buffer);
console.log('数据已向客户端发送');
// 4. (可选)服务端订阅读请求事件,实时接收客户端写入的数据
socket.on('sppRead', clientNumber, (dataBuffer: ArrayBuffer) => {
// 将接收到的ArrayBuffer转为Uint8Array,便于解析
const data = new Uint8Array(dataBuffer);
if (data != null && data.length > 0) {
// 数据非空,可在此处解析数据(如转为字符串、解析指令)
console.log('接收到客户端数据:', data);
} else {
// 数据为空,添加异常处理逻辑
console.warn('接收到客户端空数据');
}
});
// 5. (可选)取消订阅读请求事件(如通信结束、不需要再接收数据时)
socket.off('sppRead', clientNumber, (dataBuffer: ArrayBuffer) => {
const data = new Uint8Array(dataBuffer);
if (data != null) {
console.log('已取消订阅,最后接收的客户端数据:', data);
} else {
console.log('已取消订阅,无未处理数据');
}
});
// 6. 通信结束后,注销服务端socket,释放资源
socket.sppCloseServerSocket(serverNumber);
console.log('服务端socket已注销,serverId:', serverNumber);
// 7. 通信结束后,注销客户端socket,释放资源
socket.sppCloseClientSocket(clientNumber);
console.log('客户端socket已注销,clientId:', clientNumber);
2、通过socket连接对端设备
该场景的核心是“HarmonyOS设备作为客户端,通过蓝牙扫描发现对端设备,获取设备MAC地址后,通过socket建立与对端的串行通信连接”,适用于跨设备互联场景,具体开发流程与源码如下:
(1)开发流程
1. 导入串行通信所需的socket模块,提供连接与数据传输API。
2. 声明依赖的系统能力SystemCapability.Communication.Bluetooth.Core,确保应用有权限访问蓝牙功能。
3. 开启设备蓝牙,这是扫描对端设备与建立连接的前提。
4. 开启BLE(低功耗蓝牙)扫描,搜索周边可连接的蓝牙设备,获取目标设备的MAC地址(deviceId)。
5. 使用获取的deviceId与SPP配置参数,调用API连接对端设备,建立稳定的socket通信链路。
(2)源码示例
// 导入串行通信所需模块
import { socket } from '@kit.ConnectivityKit';
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
// 1. 开启BLE扫描,获取对端设备的MAC地址(deviceId)
// 注:实际开发中,需通过蓝牙扫描API获取周边设备列表,此处直接模拟目标设备的MAC地址
let deviceId = 'xx:xx:xx:xx:xx:xx'; // 替换为实际扫描到的对端设备MAC地址(格式:XX:XX:XX:XX:XX:XX)
console.log('目标对端设备MAC地址:', deviceId);
// 2. 通过socket连接对端设备,建立串行通信链路
// 传入deviceId(目标设备MAC)与SPP配置参数,异步回调返回连接结果
socket.sppConnect(deviceId, {
uuid: '00001101-0000-1000-8000-00805f9b34fb', // 通用SPP协议UUID,需与对端设备一致
secure: true, // 开启加密传输,保障数据安全
type: 0 // 连接类型:0为RFCOMM类型
}, (code, socketID) => {
if (code != null) {
// 连接失败(如设备离线、UUID不匹配、权限不足),添加错误处理逻辑
console.error('连接对端设备失败,错误码:', code);
return;
} else {
// 连接成功,返回的socketID用于后续数据收发操作
console.log('连接对端设备成功,socketID:', socketID);
// 连接成功后,可在此处添加数据收发逻辑(如发送指令、接收响应)
}
});
最后
串行通信作为HarmonyOS设备互联的“底层传输纽带”,是实现多类智能场景的核心技术之一,无论是近距离的蓝牙外设交互,还是远距离的嵌入式设备数据采集,都离不开稳定、高效的串行通信能力。通过本文的讲解,相信你已掌握串行通信的基础概念、HarmonyOS的核心API设计,以及两大典型场景的开发流程,能够基于提供的源码快速落地实际项目。随着HarmonyOS生态的持续完善,串行通信技术也将不断升级,未来可能支持更多协议、更高的传输速率以及更灵活的多设备互联架构,持续关注HarmonyOS官方文档以跟进技术更新,并结合实际项目需求不断优化通信方案,让串行通信更好地服务于应用核心功能,为用户提供更流畅、更稳定的设备互联体验。



















