鸿蒙TCPSocket通信模拟智能家居模拟案例
效果图
一、智能家居热潮下的鸿蒙契机
在当下科技飞速发展的时代,智能家居已如浪潮般席卷而来,深刻地改变着我们的生活方式。从能依据环境光线自动调节亮度的智能灯具,到可远程操控、精准控温的智能空调,再到实时监测健康数据的智能穿戴设备,智能家居产品如繁星般点缀着现代家庭,让生活愈发便捷、舒适与高效。
据权威数据显示,全球智能家居市场规模正以惊人的速度逐年攀升。2023 年,全球拥有智能家居设备的家庭数量已高达 3.61 亿户,市场销售收入更是接近 1400 亿美元。在国内,智能家居行业同样蓬勃发展,营收规模从 2018 年的 1.87 万亿跃升至 2022 年的 2.33 万亿元。英国以 45.83% 的智能家居渗透率位居全球之首,美国也达到了 43.80%,尽管我国目前的渗透率仅为 16.63%,但随着技术的日益成熟与消费者需求的迅猛增长,未来的发展潜力不可限量。
在这股智能家居的热潮中,华为鸿蒙系统崭露头角,成为了众多消费者与开发者瞩目的焦点。鸿蒙系统凭借其独特的分布式架构设计理念,打破了设备之间的隔阂,让数据能够自由、高效地流通共享。想象一下,你只需通过手机,便能轻松掌控家中的智能灯泡、空调、安全监控系统等各类设备,实现无缝对接的智能化交互体验。更为惊艳的是,鸿蒙系统融入的人工智能技术,能深度学习用户的日常习惯,提前为你调整好设备状态。例如,它会记住你每晚十点关闭客厅灯光的习惯,久而久之,为你量身打造出一个专属的智能家居生态圈。
众多行业专家也对鸿蒙系统在智能家居领域的表现给予了高度评价。技术分析师李华指出:“华为鸿蒙系统的推出代表了中国科技公司在全球市场中的一次重要跃进,是人工智能与传统家居领域结合的典范。” 它不仅为智能家居带来了前所未有的技术进步,更为用户开启了全新的智能生活体验之门。
二、鸿蒙系统与 TCPSocket 初相识
(一)鸿蒙系统架构精析
鸿蒙系统以其独特精妙的架构设计傲立科技潮头。从底层逐步向上剖析,内核层作为基石,犹如精密的发动机,掌控着硬件资源调配、进程精细调度、内存高效管理以及文件系统的稳健运作,为上层建筑筑牢根基,确保系统平稳、高效运行。系统服务层宛如万能工具库,涵盖电源管理、网络调配、安全护卫、图形渲染、音频处理等多样功能模块,为框架层与应用层输送源源不断的强大助力,大幅削减重复开发的繁琐工序。框架层恰似贴心向导,为开发者精心打造开发框架与便捷的 API 接口,降低开发门槛,提速开发进程,无论是 UI 界面的精美搭建,还是数据管理的有序组织,亦或是通信连接的顺畅保障,都能轻松驾驭。最上层的应用层,则是百花齐放的舞台,各类应用程序琳琅满目,满足用户多元需求。
这种分层架构的优势显著。模块化特性使得各层相对独立,恰似积木拼图,开发人员可聚焦某一层级深耕细作,维护升级时也能精准定位,互不干扰,极大提升开发效率与系统稳定性。可扩展性更是一绝,以智能家居开发为例,随着新设备、新功能不断涌现,各层能够灵活应变,轻松拓展,随时接纳智能门锁、空气净化器等新成员融入智能家居大家庭,为用户带来持续升级的智慧体验。安全性方面,层层设防,严格隔离,如坚固堡垒,从内核层的底层防护,到系统服务层的权限管控,再到框架层与应用层的数据加密,全方位守护用户隐私与系统安全,让用户无后顾之忧。
(二)TCPSocket 通信解密
在网络通信的浩瀚星空中,TCP 协议无疑是一颗最为耀眼的恒星。它遵循着一套严谨且精妙的规则,致力于在复杂多变、充满不确定性的网络环境中,搭建起一条稳固可靠的数据传输高速公路。
TCP 协议的工作原理好似一场精心编排的舞蹈。在数据传输的序曲奏响之前,双方必先通过三次握手来建立连接,这是确保通信顺畅的重要前奏。客户端率先发送带有 SYN 标志的同步报文段,向服务器热情 “打招呼”,表明自己的通信意愿;服务器收到后,迅速响应,回以 SYN + ACK 报文段,既确认客户端的请求,又发出自己的同步信号;客户端再发送 ACK 报文段,至此,双方确认彼此身份,连接正式建立,犹如两位舞者携手步入舞池,准备共舞。
进入数据传输阶段,TCP 为每个数据包精心标注序号,就像为信件编号一样,确保接收方能够按照正确顺序重组信息,避免乱序带来的混乱。同时,接收方每成功接收一个数据包,便会即刻发送 ACK 确认报文,告知发送方数据已安全 “着陆”。倘若发送方在预设的时间内未收到确认,便会敏锐察觉可能出现的丢包情况,迅速启动重传机制,补发丢失的数据包,犹如快递员发现包裹未送达,及时折返重新派送,确保信息不遗漏。
与 UDP 协议相比,TCP 的可靠性优势尽显。UDP 如同风一般自由随性,它是无连接的,数据发送后便 “不管不顾”,虽然传输效率颇高,能快速将数据送出,但在网络状况不佳时,极易出现丢包、乱序等问题,如同信件在风中飘散,难以保证完整送达。而 TCP 恰似忠诚的信使,凭借连接管理、确认应答、超时重传等一系列严谨机制,确保信件准确无误地递交到收件人手中,数据完整性与顺序性得到坚实保障。
在智能家居场景中,TCP 的可靠性更是不可或缺。以智能摄像头为例,它实时捕捉家中的画面,通过网络传输至用户手机端。若采用不可靠的 UDP 协议,画面可能出现卡顿、花屏甚至丢失关键信息等状况,让用户无法及时掌握家中动态,安防功能大打折扣;而 TCP 协议则能稳稳地传输每一帧画面,让用户清晰、流畅地查看家中实时情况,为家庭安全保驾护航。又如智能窗帘的控制指令传输,TCP 确保指令准确执行,避免窗帘开合失常,为用户营造舒适便捷的家居环境。
三、实战!模拟智能家居搭建全流程
(一)开发环境巧搭建
工欲善其事,必先利其器。在开启鸿蒙智能家居开发之旅前,精心搭建完备的开发环境至关重要。
硬件层面,鸿蒙开发板是关键所在。以润和 Hi3861 开发板为例,它凭借小巧灵活、功耗低微且性能稳定的特性备受青睐。其内置高性能处理器,能够快速、精准地处理各类智能家居指令,无论是控制灯光的细微亮度调节,还是空调的复杂温度调控,都能轻松应对。丰富的接口更是一绝,GPIO 接口可便捷连接各类传感器与执行器,像智能温湿度传感器、智能窗帘电机等,为智能家居设备的拓展提供了无限可能;Wi-Fi 模块确保设备稳定接入网络,实现远程通信与控制,让你即便身处千里之外,也能随心掌控家中设备。
软件方面,鸿蒙 SDK 与 DevEco Studio 堪称两大得力助手。鸿蒙 SDK 如同百宝箱,涵盖了丰富多样的开发工具、类库以及 API 接口,为开发者提供了全方位的开发支持。从基础的系统功能调用,到复杂的分布式通信实现,都能在其中找到对应的资源。DevEco Studio 则是基于 IntelliJ IDEA Community 开源版本精心打造的一站式集成开发环境(IDE)。它界面友好、操作便捷,为开发者提供了从工程模板创建、代码编写、调试测试,到最终应用发布的全流程服务。其智能代码提示功能,如同贴心助手,能在你编写代码时快速给出精准建议,大幅提升开发效率;强大的调试工具,能够帮助你迅速定位并解决代码中的问题,确保开发进程顺利推进。
(二)代码编写分步走
1. 界面设计展风貌
利用 ArkUI 进行交互界面设计,为用户打造便捷舒适的操控体验。想象一下,当你打开智能家居控制应用,映入眼帘的是布局合理、美观大方的操作界面。以下是部分关键代码示例:
客户端:
import { ToggleCom } from '../commons/component/toggleCom';
import { SWITCH } from '../commons/constant/switchCon';
import { tcpUtils } from '../commons/utils/tcpUtils';
@Entry
@Component
struct TcpClientPage {
//连接状态
@State connectState: boolean = false;
//客厅开关
@State KTState: boolean = false;
//卧室开关
@State WSState: boolean = false;
//卫生间开关
@State CSState: boolean = false;
@State
@Watch('msgChange')
msg: string = ''
intervalID = -1
@State WSD: boolean = false
@State WSK: boolean = false
@State WST: boolean = false
@State WSC: boolean = false
@State KTD: boolean = false
@State KTK: boolean = false
@State KTT: boolean = false
@State KTC: boolean = false
@State CSD: boolean = false
@State CSR: boolean = false
// 页面初始化
aboutToAppear() {
this.connectServer();
}
//连接服务器
async connectServer() {
// 绑定本地IP
await tcpUtils.bindLocalIP();
// 连接服务器
await tcpUtils.connectServer();
// 监听连接状态
this.connectState = tcpUtils.connectState;
// 监听服务器消息
this.intervalID = setInterval(() => {
this.msgChange()
}, 300)
}
msgChange() {
if (tcpUtils.serverMessage.length > 0) {
this.msg = tcpUtils.serverMessage
this.switchChange()
this.totalChange()
tcpUtils.serverMessage = ''
}
}
switchChange() {
switch (this.msg) {
case SWITCH.WSD_ON:
this.WSD = true
this.WSState = true
break
case SWITCH.WSD_OFF:
this.WSD = false
break
case SWITCH.WSK_ON:
this.WSK = true
this.WSState = true
break
case SWITCH.WSK_OFF:
this.WSK = false
break
case SWITCH.WST_ON:
this.WST = true
this.WSState = true
break
case SWITCH.WST_OFF:
this.WST = false
break
case SWITCH.WSC_ON:
this.WSC = true
this.WSState = true
break
case SWITCH.WSC_OFF:
this.WSC = false
break
case SWITCH.KTD_ON:
this.KTD = true
this.KTState = true
break
case SWITCH.KTD_OFF:
this.KTD = false
break
case SWITCH.KTK_ON:
this.KTK = true
this.KTState = true
break
case SWITCH.KTK_OFF:
this.KTK = false
break
case SWITCH.KTT_ON:
this.KTT = true
this.KTState = true
break
case SWITCH.KTT_OFF:
this.KTT = false
break
case SWITCH.KTC_ON:
this.KTC = true
this.KTState = true
break
case SWITCH.KTC_OFF:
this.KTC = false
break
case SWITCH.CSD_ON:
this.CSD = true
this.CSState = true
break
case SWITCH.CSD_OFF:
this.CSD = false
break
case SWITCH.CSR_ON:
this.CSR = true
this.CSState = true
break
case SWITCH.CSR_OFF:
this.CSR = false
break
default:
break
}
}
totalChange() {
if (!this.WSD && !this.WSK && !this.WST && !this.WSC) {
this.WSState = false
}
if (!this.KTD && !this.KTK && !this.KTT && !this.KTC) {
this.KTState = false
}
if (!this.CSD && !this.CSR) {
this.CSState = false
}
}
build() {
Column({ space: 20 }) {
// 标题栏
Row() {
Text('智能家居控制面板')
.textAlign(TextAlign.Start)
.fontWeight(FontWeight.Bold)
.fontSize(25)
.fontColor('#ffb1a67c')
.width('60%')
Row({ space: 5 }) {
Text(this.connectState ? "在线" : "离线")
.textAlign(TextAlign.End)
.fontWeight(FontWeight.Bold)
.fontSize(20)
.fontColor(this.connectState ? Color.Green : Color.Gray)
.width(48)
Text('')
.backgroundColor(this.connectState ? Color.Green : Color.Gray)
.width(12)
.height(12)
.borderRadius(6)
}
.justifyContent(FlexAlign.Center)
.border({
color: Color.Black,
width: 1.8,
radius: 15
})
.width(80)
.height(30)
.onClick(() => {
if (!this.connectState) {
this.connectServer();
} else {
tcpUtils.connectClose();
}
this.connectState = !this.connectState;
})
}
// 内容区
ToggleCom({
title: "卧室 总开关",
txtOn: SWITCH.WS_ON,
txtOff: SWITCH.WS_OFF,
isSwitch: this.WSState,
connectState: this.connectState,
onSwitch: () => {
this.WSState = !this.WSState;
this.WSD = this.WSState
this.WSK = this.WSState
this.WST = this.WSState
this.WSC = this.WSState
}
})
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.WSD,
txtOn: SWITCH.WSD_ON,
txtOff: SWITCH.WSD_OFF,
connectState: this.connectState,
onSwitch: () => {
this.WSState = true
this.WSD =!this.WSD;
this.totalChange()
}
})
ToggleCom({
isSwitch: this.WSK,
txtOn: SWITCH.WSK_ON,
txtOff: SWITCH.WSK_OFF,
connectState: this.connectState,
ImgOn: $r('app.media.air_on'),
ImgOff: $r('app.media.air_off'),
onSwitch: () => {
this.WSState = true
this.WSK =!this.WSK;
this.totalChange()
}
})
}
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.WST,
txtOn: SWITCH.WST_ON,
txtOff: SWITCH.WST_OFF,
connectState: this.connectState,
ImgOn: $r('app.media.lamp_on'),
ImgOff: $r('app.media.lamp_off'),
onSwitch: () => {
this.WSState = true
this.WST =!this.WST;
this.totalChange()
}
})
ToggleCom({
isSwitch: this.WSC,
txtOn: SWITCH.WSC_ON,
txtOff: SWITCH.WSC_OFF,
connectState: this.connectState,
ImgOn: $r('app.media.curtain_on'),
ImgOff: $r('app.media.curtain_off'),
onSwitch: () => {
this.WSState = true
this.WSC =!this.WSC;
this.totalChange()
}
})
}
ToggleCom({
title: "客厅 总开关",
txtOn: SWITCH.KT_ON,
txtOff: SWITCH.KT_OFF,
isSwitch: this.KTState,
connectState: this.connectState,
onSwitch: () => {
this.KTState = !this.KTState;
this.KTD = this.KTState
this.KTK = this.KTState
this.KTT = this.KTState
this.KTC = this.KTState
}
})
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.KTD,
txtOn: SWITCH.KTD_ON,
txtOff: SWITCH.KTD_OFF,
connectState: this.connectState,
onSwitch: () => {
this.KTState = true
this.KTD =!this.KTD;
this.totalChange()
}
})
ToggleCom({
isSwitch: this.KTK,
txtOn: SWITCH.KTK_ON,
txtOff: SWITCH.KTK_OFF,
ImgOn: $r('app.media.air_on'),
ImgOff: $r('app.media.air_off'),
onSwitch: () => {
this.KTState = true
this.KTK = !this.KTK;
this.totalChange()
}
})
}
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.KTT,
txtOn: SWITCH.KTT_ON,
txtOff: SWITCH.KTT_OFF,
connectState: this.connectState,
ImgOn: $r('app.media.tv_on'),
ImgOff: $r('app.media.tv_off'),
onSwitch: () => {
this.KTState = true
this.KTT =!this.KTT;
this.totalChange()
}
})
ToggleCom({
isSwitch: this.KTC,
txtOn: SWITCH.KTC_ON,
txtOff: SWITCH.KTC_OFF,
connectState: this.connectState,
ImgOn: $r('app.media.curtain_on'),
ImgOff: $r('app.media.curtain_off'),
onSwitch: () => {
this.KTState = true
this.KTC =!this.KTC;
this.totalChange()
}
})
}
ToggleCom({
title: "卫生间 总开关",
txtOn: SWITCH.CS_ON,
txtOff: SWITCH.CS_OFF,
isSwitch: this.CSState,
connectState: this.connectState,
onSwitch: () => {
this.CSState = !this.CSState;
this.CSD = this.CSState
this.CSR = this.CSState
}
})
Row({ space: 5 }) {
ToggleCom({
connectState: this.connectState,
isSwitch: this.CSD,
txtOn: SWITCH.CSD_ON,
txtOff: SWITCH.CSD_OFF,
onSwitch: () => {
this.CSState = true
this.CSD =!this.CSD;
this.totalChange()
}
})
ToggleCom({
isSwitch: this.CSR,
txtOn: SWITCH.CSR_ON,
txtOff: SWITCH.CSR_OFF,
connectState: this.connectState,
ImgOn: $r('app.media.water_on'),
ImgOff: $r('app.media.water_off'),
onSwitch: () => {
this.CSState = true
this.CSR =!this.CSR;
this.totalChange()
}
})
}
}
.height('100%')
.width('100%')
.backgroundColor('#F4F3EF')
}
}
服务端:
import { ToggleCom } from '../commons/component/toggleCom';
import { SWITCH } from '../commons/constant/switchCon';
import { tcpUtils } from '../commons/utils/tcpUtils';
@Entry
@Component
struct TcpServerPage {
@State
@Watch('msgChange')
msg: string = ''
intervalID = -1
@State WSD: boolean = false
@State WSK: boolean = false
@State WST: boolean = false
@State WSC: boolean = false
@State KTD: boolean = false
@State KTK: boolean = false
@State KTT: boolean = false
@State KTC: boolean = false
@State CSD: boolean = false
@State CSR: boolean = false
aboutToAppear() {
tcpUtils.listenServer()
this.intervalID = setInterval(() => {
this.msgChange()
}, 300)
}
msgChange() {
if (tcpUtils.messageData.length > 0) {
this.msg = tcpUtils.messageData
this.switchChange()
}
}
switchChange() {
switch (this.msg) {
case SWITCH.WS_ON:
this.WSD = true
this.WSK = true
this.WST = true
this.WSC = true
break
case SWITCH.WS_OFF:
this.WSD = false
this.WSK = false
this.WST = false
this.WSC = false
break
case SWITCH.KT_ON:
this.KTD = true
this.KTK = true
this.KTT = true
this.KTC = true
break
case SWITCH.KT_OFF:
this.KTD = false
this.KTK = false
this.KTT = false
this.KTC = false
break
case SWITCH.CS_ON:
this.CSD = true
this.CSR = true
break
case SWITCH.CS_OFF:
this.CSD = false
this.CSR = false
break
case SWITCH.WSD_ON:
this.WSD = true
break
case SWITCH.WSD_OFF:
this.WSD = false
break
case SWITCH.WSK_ON:
this.WSK = true
break
case SWITCH.WSK_OFF:
this.WSK = false
break
case SWITCH.WST_ON:
this.WST = true
break
case SWITCH.WST_OFF:
this.WST = false
break
case SWITCH.WSC_ON:
this.WSC = true
break
case SWITCH.WSC_OFF:
this.WSC = false
break
case SWITCH.KTD_ON:
this.KTD = true
break
case SWITCH.KTD_OFF:
this.KTD = false
break
case SWITCH.KTK_ON:
this.KTK = true
break
case SWITCH.KTK_OFF:
this.KTK = false
break
case SWITCH.KTT_ON:
this.KTT = true
break
case SWITCH.KTT_OFF:
this.KTT = false
break
case SWITCH.KTC_ON:
this.KTC = true
break
case SWITCH.KTC_OFF:
this.KTC = false
break
case SWITCH.CSD_ON:
this.CSD = true
break
case SWITCH.CSD_OFF:
this.CSD = false
break
case SWITCH.CSR_ON:
this.CSR = true
break
case SWITCH.CSR_OFF:
this.CSR = false
break
default:
break
}
}
build() {
Column({ space: 20 }) {
// 标题栏
Row() {
Text('智能家居模拟家电')
.textAlign(TextAlign.Start)
.fontWeight(FontWeight.Bold)
.fontSize(25)
.fontColor('#ffb1a67c')
.width('60%')
}
// 内容区
ToggleCom({
title: "卧室 "
})
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.WSD,
txtOn: SWITCH.WSD_ON,
txtOff: SWITCH.WSD_OFF,
})
ToggleCom({
isSwitch: this.WSK,
txtOn: SWITCH.WSK_ON,
txtOff: SWITCH.WSK_OFF,
ImgOn: $r('app.media.air_on'),
ImgOff: $r('app.media.air_off')
})
}
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.WST,
txtOn: SWITCH.WST_ON,
txtOff: SWITCH.WST_OFF,
ImgOn: $r('app.media.lamp_on'),
ImgOff: $r('app.media.lamp_off')
})
ToggleCom({
isSwitch: this.WSC,
txtOn: SWITCH.WSC_ON,
txtOff: SWITCH.WSC_OFF,
ImgOn: $r('app.media.curtain_on'),
ImgOff: $r('app.media.curtain_off')
})
}
ToggleCom({
title: "客厅",
})
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.KTD,
txtOn: SWITCH.KTD_ON,
txtOff: SWITCH.KTD_OFF,
})
ToggleCom({
isSwitch: this.KTK,
txtOn: SWITCH.KTK_ON,
txtOff: SWITCH.KTK_OFF,
ImgOn: $r('app.media.air_on'),
ImgOff: $r('app.media.air_off')
})
}
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.KTT,
txtOn: SWITCH.KTT_ON,
txtOff: SWITCH.KTT_OFF,
ImgOn: $r('app.media.tv_on'),
ImgOff: $r('app.media.tv_off')
})
ToggleCom({
isSwitch: this.KTC,
txtOn: SWITCH.KTC_ON,
txtOff: SWITCH.KTC_OFF,
ImgOn: $r('app.media.curtain_on'),
ImgOff: $r('app.media.curtain_off')
})
}
ToggleCom({
title: "卫生间"
})
Row({ space: 5 }) {
ToggleCom({
isSwitch: this.CSD,
txtOn: SWITCH.CSD_ON,
txtOff: SWITCH.CSD_OFF,
})
ToggleCom({
isSwitch: this.CSR,
txtOn: SWITCH.CSR_ON,
txtOff: SWITCH.CSR_OFF,
ImgOn: $r('app.media.water_on'),
ImgOff: $r('app.media.water_off')
})
}
}
.height('100%')
.width('100%')
.backgroundColor('#F4F3EF')
}
}
在上述代码中,通过Column和Row组件巧妙布局,将灯光、窗帘、空调等设备的控制按钮有序排列。@State装饰器用于绑定设备状态,使其能够实时响应变化并在界面上精准展示。每个按钮的onClick事件则为后续添加控制逻辑预留了接口,为实现设备的远程操控搭建了基础框架。
2. TCPSocket 通信代码实现
在鸿蒙系统中,借助@ohos.net.socket模块实现 TCPSocket 通信。核心代码如下:
客户端:
import { socket } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { buf2S } from './buftoString';
class TcpUtils {
// 2. **创建连接:**创建一个 TCPSocket 连接,返回一个 TCPSocket 对象。
tcpConnect: socket.TCPSocket = socket.constructTCPSocketInstance();
localIp: string = '127.0.0.1';
localPort: number = 4651
serverIp: string = '127.0.0.1';
serverPort: number = 8000
bindState: string = "未绑定"
connectState: boolean = false
sendMessage: string = ''
serverMessage: string = ''
canSend: boolean = false
// 4. **绑定IP和端口:**绑定 IP 地址和端口,端口可以指定或由系统随机分配。
async bindLocalIP() {
// 绑定本地IP地址和端口。
let ipAddress: socket.NetAddress = {
address: this.localIp,
port: this.localPort,
// 1: IPv4, 2: IPv6
family: 1
}
await this.tcpConnect.bind(ipAddress).then(() => {
console.info('===bind success!===');
this.bindState = "bind success!"
}).catch((err: BusinessError) => {
console.info('===bind failed!===', JSON.stringify(err));
})
}
async connectServer() {
let serverAddress: socket.NetAddress = {} as socket.NetAddress;
serverAddress.address = this.serverIp;
serverAddress.port = this.serverPort;
serverAddress.family = 1
await this.tcpConnect.connect({ address: serverAddress })//三次握手
.then(() => {
console.info('===connect success!=== ')
this.canSend = true
this.connectState = true
3. (**可选**)订阅 TCPSocket 相关的订阅事件。接收数据
//收到消息时的处理
this.tcpConnect.on("message", async (value: socket.SocketMessageInfo) => {
let msg: string = buf2S.buf2String(value.message)
console.info("===服务端:" + msg)
this.serverMessage = msg
})
})
.catch((err: BusinessError) => {
console.info('===connect fail!===' + JSON.stringify(err))
})
}
// 6. **通信:** 发送消息到服务端。
sendData(message: string) {
if (this.canSend) {
this.tcpConnect.send({ data: message })//data的数据格式可以定制
.then(async () => {
console.info('===数据发送成功!===')
}).catch(() => {
console.info('===数据发送失败!===')
})
}
}
// 7. **断开连接:**Socket 连接使用完毕后,主动关闭。
connectClose() {
this.tcpConnect.close(() => {
console.info('===closed!===')
this.connectState = false
})
}
}
export const tcpUtils = new TcpUtils()
服务端:
import { socket } from '@kit.NetworkKit';
import { BusinessError, emitter } from '@kit.BasicServicesKit';
class SocketInfo {
message: ArrayBuffer = new ArrayBuffer(1);
remoteInfo: socket.SocketRemoteInfo = {} as socket.SocketRemoteInfo;
}
class TcpUtils {
tcpServer: socket.TCPSocketServer = socket.constructTCPSocketServerInstance();
serverIp: string = '127.0.0.1'
serverPort: number = 8000
serverData: string = ''
//接收到的消息
messageData: string = "";
private connectState: boolean = false
private tcpSocketConnection ?: socket.TCPSocketConnection
async listenServer() {
let ipAddress: socket.NetAddress = {
address: this.serverIp,
port: this.serverPort,
}
// 绑定IP:Port、监听并启动服务,接收客户端的连接请求
this.tcpServer.listen(ipAddress).then(() => {
console.info('===listen success===');
this.tcpServer.on("connect", (tcpConnection: socket.TCPSocketConnection) => {
console.info("===connect success====")
this.connectState = true
this.tcpSocketConnection = tcpConnection
tcpConnection.on("message", (data: SocketInfo) => {
console.info("====receive message====")
let buffer = data.message;
let dataView = new DataView(buffer);
this.messageData = ""
for (let i = 0; i < dataView.byteLength; ++i) {
this.messageData += String.fromCharCode(dataView.getUint8(i));
}
console.log("===" + this.messageData)
});
// 订阅TCPSocketConnection相关的事件
tcpConnection.on("close", () => {
console.info("===断开连接===");
});
})
}).catch((err: BusinessError) => {
console.info('listen fail', JSON.stringify(err));
});
}
async sendData(message: string) {
if (this.connectState) { //连接成功才可发送数据
// 服务端给连接的客户端发送信息
let tcpSendOptions: socket.TCPSendOptions = {} as socket.TCPSendOptions;
tcpSendOptions.data = message
this.tcpSocketConnection?.send(tcpSendOptions).then(() => {
console.info('===send success===');
})
}
}
}
export const tcpUtils = new TcpUtils()
这段代码清晰地展现了 TCPSocket 通信的关键步骤。首先,通过constructTCPSocketInstance创建套接字实例,这是通信的起点。接着,使用bind方法绑定本地 IP 地址与端口,确保设备在网络中的标识唯一,如同为设备在网络世界中找到一个专属的 “停车位”。然后,connect方法用于与服务器建立连接,打通数据传输的通道。on方法实现接收消息的监听,一旦有数据从服务器传来,便能及时捕捉并处理。最后,send方法则用于向服务器发送数据,实现设备与服务器之间的双向通信。
3. 设备控制逻辑显神通
以控制智能灯光设备为例,结合 TCPSocket 通信实现设备控制逻辑。当用户在界面点击灯光 “打开” 按钮时,执行如下代码:
totalChange() {
if (!this.WSD && !this.WSK && !this.WST && !this.WSC) {
this.WSState = false
}
if (!this.KTD && !this.KTK && !this.KTT && !this.KTC) {
this.KTState = false
}
if (!this.CSD && !this.CSR) {
this.CSState = false
}
}
在这段代码中,定义了一个名为 totalChange 的函数。这个函数的作用是根据各个子开关的状态来更新总开关的状态。具体来说,如果所有的卧室设备开关(WSD、WSK、WST、WSC)都处于关闭状态,那么卧室总开关(WSState)也会被设置为关闭状态。同样,如果所有的客厅设备开关(KTD、KTK、KTT、KTC)都处于关闭状态,那么客厅总开关(KTState)也会被设置为关闭状态。最后,如果窗帘开关(CSD)或窗帘复位开关(CSR)中有一个处于关闭状态,那么窗帘总开关(CSState)也会被设置为关闭状态。
这个函数的实现逻辑清晰,通过检查各个子开关的状态来决定总开关的状态。这种设计可以确保总开关的状态能够准确反映所有子开关的状态,从而实现对整个系统的有效控制
四、案例优化与拓展探索
(一)性能瓶颈巧突破
随着智能家居设备数量的不断增加,系统可能面临多设备连接下的延迟、卡顿等性能瓶颈。例如,当家中同时有多个智能设备频繁向服务器发送或接收数据时,网络带宽可能会出现拥堵,如同上下班高峰期的城市道路,数据传输受阻,导致控制指令延迟执行,用户体验大打折扣。
为优化性能,可从多方面入手。一方面,优化数据传输格式,采用精简高效的 JSON 或二进制格式替代冗长的数据格式,减少数据传输量,就像将货物精简打包后运输,提高传输效率;另一方面,合理设置缓冲区大小,根据设备实际需求动态调整,避免数据溢出或等待时间过长,确保数据传输平稳流畅。此外,引入数据缓存机制,对于频繁访问的数据如设备状态信息,存储在本地缓存中,下次请求时可直接从缓存读取,减少与服务器的交互次数,加快响应速度,如同在本地设立了一个小型数据仓库,随时满足快速取用的需求。
(二)功能拓展创无限
为使智能家居系统更加智能便捷,可进一步拓展功能。想象一下,清晨醒来,你无需动手操作手机,只需轻声说出 “打开卧室灯光,拉开窗帘”,智能系统便能精准识别你的语音指令,为你开启活力满满的一天;夜晚回家,一句 “开启观影模式”,灯光自动调暗,窗帘缓缓拉上,电视播放你喜爱的节目,让你瞬间放松身心。
要实现语音控制功能,可借助鸿蒙系统的语音识别与语义解析能力。通过集成语音识别引擎,将用户的语音指令转化为文本,再利用语义解析技术提取关键信息,与预设的控制指令匹配,最后通过 TCPSocket 通信发送给相应设备执行操作。例如,当识别到 “打开客厅灯” 的语音指令,解析后找到对应的灯光设备控制代码,发送开灯指令,灯光随即亮起。
场景模式的实现则需建立不同场景下设备状态的预设集合。以 “睡眠模式” 为例,系统将灯光亮度调至最暗、关闭不必要电器、设置空调适宜睡眠的温度等,用户一键切换场景,即可享受全方位的智能服务。这需要在代码层面精心设计场景切换逻辑,关联多个设备的控制指令,为用户打造个性化、沉浸式的智能家居体验。
五、项目复盘与未来展望
回顾整个项目历程,诸多难点犹如崎岖山路,考验着开发者的智慧与毅力。在鸿蒙系统学习初期,其独特的分布式架构与全新的开发理念,宛如神秘的知识迷宫,让人一时摸不着头脑。但随着深入钻研,如同拨云见日,逐步领悟到其精妙之处,为后续开发点亮了明灯。
TCPSocket 通信的实现过程也并非一帆风顺。不同设备间的网络适配问题频出,就像为性格各异的人挑选合身衣物,需反复调试参数,确保通信顺畅。在设备控制逻辑与界面交互的衔接环节,也常出现 “沟通不畅” 的状况,按钮点击后无响应或延迟响应,让人头疼不已。经过无数次的代码审查、逻辑梳理,才使得两者默契配合,实现流畅操控。
展望未来,鸿蒙在智能家居领域的前景一片光明。随着技术的持续升级,智能家居系统将愈发智能、便捷、人性化。想象一下,未来的智能家居系统能够依据你的情绪状态自动调节环境氛围,当你疲惫时,柔和的灯光、舒缓的音乐随即开启;借助更强大的人工智能算法,精准预测你的生活需求,提前准备好热水、调整室内温度;在安全防护层面,与智能安防系统深度融合,一旦有异常情况,立即联动报警并推送详细信息至你的手机。
鸿蒙系统将如同一颗闪耀的火种,点燃智能家居领域创新的燎原之火,引领我们迈向一个更加智能、美好的生活时代,让家真正成为温馨、舒适、智慧的港湾。
六、TCPSocket通信拓展
Socket 连接:主要是通过 Socket 进行数据传输,支持 TCP/UDP/Multicast/TLS 协议。
Socket:套接字,就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。
TCP:传输控制协议(Transmission Control Protocol)。是一种面向连接的、可靠的、基于字节流的传输层通信协议。
UDP:用户数据报协议(User Datagram Protocol)。是一个简单的面向消息的传输层,不需要连接。
应用场景,如
客户端:应用通过 TCP/UDP Socket进行数据传输
服务端:应用通过 TCP Socket Server 进行数据传输.鸿蒙操作系统中,Socket 连接主要由 socket模块提供,模块提供了多种API供开发者调用。
TCP客户端
TCP客户端实现的流程:
1.导入库: import 需要的 socket 模块。
2.创建连接:创建一个 TCPSocket 连接,返回一个 TCPSocket 对象。
3.(可选)订阅 TCPSocket 相关的订阅事件。
4.绑定IP和端口: 绑定 『 地址和端口,端口可以指定或由系统随机分配。
5.连接服务器:连接到指定的 IP 地址和端口。
6.发送消息:发送数据。
7.断开连接: Socket连接使用完毕后,主动关闭。
涉及的API以及功能说明:
TCP服务端
1.import 需要的 socket 模块。
2.创建一个 TCPSocketServer 连接,返回一个 TCPSocketServer 对象。
3.绑定本地 IP 地址和端口,监听并接受与此套接字建立的客户端 TCPSocket 连接。
4.订阅 TCPSocketServer 的 connect 事件,用于监听客户端的连接状态。
5.客户端与服务端建立连接后,返回一个 TCPSocketConnection 对象,用于与客户端通信。
6.订阅 TCPSocketConnection 相关的事件,通过 TCPSocketConnection 向客户端发送数据。
7.主动关闭与客户端的连接。
8.取消 TCPSocketConnection 和 TCPSocketServer 相关事件的订阅。
本地模拟器做服务端
IP端口映射
以管理员身份运行命令提示符
电脑IP和本地模拟器IP端口映射
在命令行输入以下代码
netsh interface portproxy add v4tov4 listenaddress=你的电脑的IP地址 listenport=8888 connectaddress=127.0.0.1 connectport=8000
不知道ip地址可以输入 ipconfig
显示映射结果
netsh interface portproxy show v4tov4
设置端口转发
首先启动本地模拟器
在进行端口转发前,一定要先启动本地模拟器,即 本地模拟器每次重启都需要重新设备端口转发
接下来需要配置鸿蒙模拟器端口转发,使用HDC命令操作,需要用到hdc.exe
文件,该文件在OpenHarmony SDK目录下的\toolchains
目录内部找到(每个人的路径不同),需要记住该目录。例如我的电脑上hdc.exe的路径:
进入toolchains目录,在命令行执行以下命令进行端口转发:
注意:本地模拟器每次重启都需要重新进行端口转发
hdc.exe -t 127.0.0.1:5555 fport tcp:8000 tcp:8000
配置环境变量 (可能需要)
OHOS_HDC_SERVER_PORT