HarmonyOS开发实战:UDP通讯示例规范

 1. UDP简介

UDP协议是传输层协议的一种,它不需要建立连接,是不可靠、无序的,相对于TCP协议报文更简单,在特定场景下有更高的数据传输效率,在现代的网络通讯中有广泛的应用,以最新的HTTP/3为例,它是基于QUIC(Quick UDP Internet Connections)协议的,从协议名字就不难看出,这个基础协议也是UDP的,现在就扔掉对UDP的偏见,深入、彻底的了解UDP,从而更好地掌握鸿蒙网络编程。

2. UDP通讯的常用方法

鸿蒙封装的UDP操作类位于模块socket中,使用如下的方式导入:

import socket from '@ohos.net.socket';

        socket模块包括了众多的UDP操作方法,就本文而言,重点需要掌握的是如下四个:

1)constructUDPSocketInstance(): UDPSocket

创建一个UDPSocket对象,在使用UDPSocket的方法以前需要创建该对象。

2)bind(address: NetAddress): Promise<void>

绑定IP地址和端口,端口可以指定或由系统随机分配,可以使用0.0.0.0表示本机IP地址;使用Promise方式作为异步方法。

3)send(options: UDPSendOptions): Promise<void>

通过UDPSocket连接发送数据,因为UDP是无连接的,给定IP地址和端口即可发送数据,不用考虑对方是否真的存在;使用Promise方式作为异步方法。

4)on(type: 'message', callback: Callback<{message: ArrayBuffer, remoteInfo: SocketRemoteInfo}>): void

订阅UDPSocket连接的接收消息事件,当套接字接收到消息时触发该事件,其中message表示接收到的消息,remoteInfo是发送方信息;使用callback方式作为异步方法。

除了这些方法,为了得到系统IP地址,还使用了wifiManager模块的getIpInfo方法,该方法并不是UDP通讯必须的,就不详细介绍了。

3. UDP通讯示例

为演示UDP通讯的方式,本示例实现了一个使用UDP协议发送、接收消息的功能,运行后的界面如下所示:

cke_203578.png

下面详细介绍创建该应用的步骤。

步骤1:创建Empty Ability项目。

步骤2:在module.json5配置文件加上对权限的声明:

"requestPermissions": [

      {

        "name": "ohos.permission.INTERNET"

      },

      {

        "name": "ohos.permission.GET_WIFI_INFO"

      }

    ]

这里分别添加了访问互联网和访问WIFI信息的权限。

步骤3:在Index.ets文件里添加如下的代码:

import socket from '@ohos.net.socket';
import wifiManager from '@ohos.wifiManager';
import systemDateTime from '@ohos.systemDateTime';
import util from '@ohos.util';//执行UDP通讯的对象
let udpSocket = socket.constructUDPSocketInstance();//说明:本地的IP地址不是必须知道的,绑定时绑定到IP:0.0.0.0即可,显示本地IP地址的目的是方便对方发送信息过来
//本地IP的数值形式
let ipNum = wifiManager.getIpInfo().ipAddress
//本地IP的字符串形式
let localIp = (ipNum >>> 24) + '.' + (ipNum >> 16 & 0xFF) + '.' + (ipNum >> 8 & 0xFF) + '.' + (ipNum & 0xFF);@Entry
@Component
struct Index {//连接、通讯历史记录@State msgHistory: string = ''//要发送的信息@State sendMsg: string = ''//本地端口@State localPort: number = 9990//目的IP地址@State targetIp: string = "0.0.0.0"//目的端口@State targetPort: number = 9990scroller: Scroller = new Scroller()build() {Row() {Column() {Text("UDP通讯示例").fontSize(14).fontWeight(FontWeight.Bold).width('100%').textAlign(TextAlign.Center).padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("本地IP和端口:").width(110).fontSize(14).flexGrow(0)Text(localIp).width(80).fontSize(14).flexGrow(0)TextInput({ text: this.localPort.toString() }).type(InputType.Number).onChange((value) => {this.localPort = parseInt(value)}).width(100).flexGrow(3)Button("绑定").onClick(() => {this.bind2Port()}).width(80).fontSize(14).flexGrow(0)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("对端IP和端口:").fontSize(14).width(110).flexGrow(1)TextInput({ text: this.targetIp }).onChange((value) => {this.targetIp = value}).width(100).flexGrow(4)Text(":").width(5).flexGrow(0)TextInput({ text: this.targetPort.toString() }).type(InputType.Number).onChange((value) => {this.targetPort = parseInt(value)}).flexGrow(2).width(60)}.width('100%').padding(10)Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {TextInput({ placeholder: "输入要发送的消息" }).onChange((value) => {this.sendMsg = value}).width(200).flexGrow(1)Button("发送").width(80).flexGrow(0).onClick(() => {this.sendMsg2Target()})}.width('100%').padding(10)Scroll(this.scroller) {Text(this.msgHistory).textAlign(TextAlign.Start).padding(10).width('100%').backgroundColor(0xeeeeee)}.align(Alignment.Top).backgroundColor(0xeeeeee).height(300).flexGrow(1).scrollable(ScrollDirection.Vertical).scrollBar(BarState.On).scrollBarWidth(20)}.width('100%').justifyContent(FlexAlign.Start).height('100%')}.height('100%')}//发送消息到目的ip和端口sendMsg2Target() {//目的ip和端口let remoteAddress = { address: this.targetIp, port: this.targetPort, family: 1 }udpSocket.send({ data: this.sendMsg, address: remoteAddress }).then(async () => {this.msgHistory += "我:" + this.sendMsg + await getCurrentTimeString() + "\r\n"}).catch((e) => {this.msgHistory += '发送失败' + e.message + "\r\n";})}//绑定本地端口async bind2Port() {//本地地址let localAddress = { address: "0.0.0.0", port: this.localPort, family: 1 }await udpSocket.bind(localAddress).then(() => {this.msgHistory = 'bind success' + "\r\n";}).catch((e) => {this.msgHistory = 'bind fail' + e.message + "\r\n";})//收到消息时的处理udpSocket.on("message", async (value) => {let msg = buf2String(value.message)let remoteIP = value.remoteInfo.addresslet remotePort = value.remoteInfo.port.toString()//对端ip地址和端口的字符串形式let remoteAddr = "[" + remoteIP + ":" + remotePort + "]:"let time = await getCurrentTimeString()this.msgHistory += remoteAddr + msg + time + "\r\n"this.scroller.scrollEdge(Edge.Bottom)})}
}//同步获取当前时间的字符串形式
async function getCurrentTimeString() {let time = ""await  systemDateTime.getDate().then((date) => {time = date.getHours().toString() + ":" + date.getMinutes().toString()+ ":" + date.getSeconds().toString()})return "[" + time + "]"
}//ArrayBuffer转utf8字符串
function buf2String(buf: ArrayBuffer) {let msgArray = new Uint8Array(buf);let textDecoder = util.TextDecoder.create("utf-8");return textDecoder.decodeWithStream(msgArray)
}

步骤4:编译运行。如果通过模拟器来部署运行,需要使用远程模拟器

cke_315118.png

使用本地模拟器可能会有网络问题。

另外,使用模拟器的时候要确保打开WIFI,可以通过设置->WLAN页面开启。

步骤5:配置本地端口和对端IP地址和端口,然后单击绑定按钮绑定到本地指定的端口,再单击发送按钮发送消息。可以根据实际需要配置,如果没有对端的UDP应用,把本应用作为对端也可以,也就是相当于自己给自己发送消息,最后自己再接收,如图所示:

cke_416491.png

​这样就完成了一个简单的UDP消息发送应

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?但是又不知道从哪里下手,而且学习时频繁踩坑,最终浪费大量时间。所以本人整理了一些比较合适的鸿蒙(HarmonyOS NEXT)学习路径和一些资料的整理供小伙伴学习

 →纯血鸿蒙Next全套最新学习资料

希望这一份鸿蒙学习资料能够给大家带来帮助

                             
                                     

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vmware虚拟机安装openEuler

一、openEuler简介 openEuler是一款开源操作系统。当前openEuler内核源于Linux&#xff0c;支持鲲鹏及其它多种处理器&#xff0c;能够充分释放计算芯片的潜能&#xff0c;是由全球开源贡献者构建的高效、稳定、安全的开源操作系统&#xff0c;适用于数据库、大数据、云计算、…

EEPROM内部原理

A2, A1, A0是EEPROM的地址引脚&#xff0c;用于设置设备地址。它们的作用如下&#xff1a; 设备寻址&#xff1a; 这三个引脚允许在I2C总线上唯一地标识EEPROM芯片。通过不同的连接方式&#xff08;接高、接低或悬空&#xff09;&#xff0c;可以为同一类型的EEPROM芯片设置不同…

1uH电感SK6615电流1.5A频率2MHz输入5.5V同步降压转换器

SK6615C 1.5A 2MHz 5.5V同步降压转换器 SK6615 SOT23-5封装和丝印LA 描述 该SK6615C是一款高效、DC-DC降压型开关稳压器&#xff0c;能够提供高达1.5A的输出电流。该器件的工作输入电压范围为 2.6V 至 5.5V&#xff0c;输出电压范围为 0.6V 至 VIN。工作频率为2MHz&#xff0c…

02.C1W1.Sentiment Analysis with Logistic Regression

目录 Supervised ML and Sentiment AnalysisSupervised ML (training)Sentiment analysis Vocabulary and Feature ExtractionVocabularyFeature extractionSparse representations and some of their issues Negative and Positive FrequenciesFeature extraction with freque…

玩具租赁系统(安装+讲解+源码)

技术栈: 后端: SpringBoot Mysql MybatisPlus 前端: Vue Element 分为 管理员端 用户端 功能: 用户端 管理员端 观看地址: B站搜&#xff1a; 【毕设者】玩具租赁系统(安装讲解源码)

Java高级重点知识点-13-数据结构、List集合、List集合的子类

文章目录 数据结构List集合List的子类&#xff08;ArrayList集、LinkedList集&#xff09; 数据结构 栈 stack,又称堆栈&#xff0c;它是运算受限的线性表&#xff0c;其限制是仅允许在标的一端进行插入和删除操作&#xff0c;不允许在其他任何位置进行添加、查找、删除等操作…

cesium 添加 Echarts图层(人口迁徒图)

cesium 添加 Echarts 人口迁徒图(下面附有源码) 1、实现思路 1、在scene上面新增一个canvas画布 2、通坐标转换,将经纬度坐标转为屏幕坐标来实现 3、将ecarts 中每个series数组中元素都加 coordinateSystem: ‘cesiumEcharts’ 2、示例代码 <!DOCTYPE html> <ht…

PCIe Switch

如图所示&#xff0c;pcie Switch 被定义为多个虚拟PCI-to-PCI Bridge设备的逻辑集合。所有交换机由以下基本规则管理。 . Switch在配置软件中表现为两个或多个逻辑PCI-to-PCI桥 不需要支持下行端口作为锁定请求的发起端口. 每个enable的端口必须符合“流量控制”规范。 .S…

Linux之进程控制(上)

目录 进程创建 进程终止 进程退出码 进程终止的方式 进程等待 进程等待的方式 status概述 总结 上期我们学习了Linux中进程地址空间的概念&#xff0c;至此进程的所有基本概念已经全部学习完成&#xff0c;今天我们将开始学习进程相关的操作。 进程创建 进程创建其实…

理解MySQL存储引擎:掌握数据存储与管理

在工作或学习过程中&#xff0c;作为一名数据库管理员或开发者&#xff0c;我们常常需处理大量数据&#xff0c;同时确保数据的可靠性与高效性。MySQL作为最受欢迎的开源数据库之一&#xff0c;其强大的性能和灵活性广为人知。而在MySQL背后的存储引擎则起到了至关重要的作用。…

强对抗的 SquidLoader 针对中国企业发起攻击

研究人员近期发现了一种高对抗强度的 Loader&#xff0c;其通过钓鱼邮件附件传递给受害者。根据恶意软件所具备的引诱和规避行为&#xff0c;研究人员将其命名为 SquidLoader。SquidLoader 最早在 2024 年 4 月下旬被发现&#xff0c;但研究人员认为其至少已经活跃了一个月以上…

Vue 数据大屏适配

1、准备俩个盒子 .dataScreen-content 盒子内容根据设计稿给的px单位进行正常的布局就行 2、盒子的CSS样式 .dataScreen-container {width: 100%;height: 100%;// 有背景图需要的样式background: url("./images/bg.png") no-repeat;background-repeat: no-repeat;b…

入门PHP就来我这(纯干货)04

~~~~ 有胆量你就来跟着路老师卷起来&#xff01; -- 纯干货&#xff0c;技术知识分享 ~~~~ 路老师给大家分享PHP语言的知识了&#xff0c;旨在想让大家入门PHP&#xff0c;并深入了解PHP语言。 我们接着《想入门PHP就来我这&#xff08;纯干货&#xff09;03》继续往下学习&am…

安装Rabbitmq遇到的坑

&#xff01;&#xff01;&#xff01;一定要对号版本号 不同的虚拟机unbontu、cetenos和不同的erlang和不同的rabbitmq之间要对应下载对应版本 下面给出我的版本centos7erlangrabbitmq 分割线 安装好后&#xff0c;如果在虚拟机的服务器上可以打开&#xff0c;在本地浏览器…

JavaScript中的Array(数组)对象

目录 一、Array数组对象 1、介绍 2、创建数组对象并赋值 3、访问数组元素 二、Array对象属性 1、constructor属性 2、length属性 3、prototype属性 三、Array对象的常用方法 1、isArray() 2、concat() 3、pop() 4、shift() 5、push() 6、unshift() 7、reverse(…

高性价比宠物空气净化器分享,希喂、霍尼韦尔、有哈PK

近期&#xff0c;家中的小猫咪仿佛化身为行走的“蒲公英”&#xff0c;掉毛现象愈发严重&#xff0c;家中每个角落乃至空气中都弥漫着难以忽视的猫毛&#xff0c;衣物更是无一幸免&#xff0c;披上了毛茸茸的“外衣”。更令人啼笑皆非的是&#xff0c;就连不经意间清理的眼屎中…

VQA视觉问答系统

这是一个典型的多模态问题,融合了CV与NLP的技术,计算机需要同时学会理解图像和文字。 Joint embedding 首先,图像和问题分别由CNN和RNN进行第一次编码得到各自的特征,随后共同输入到另一个编码器中得到joint embedding,最后通过解码器输出答案。 值得注意的是,有的工作…

小红书运营教程02

小红书大致会分享10篇左右。微博、抖音、以及视频剪辑等自媒体运营相关技能以及运营教程相关会陆续的进行分享。 上次分享涉及到的对比,母婴系列,或者可以说是服装类型,不需要自己过多的投入,对比知识类博主来说,自己将知识讲述出来,然后要以此账号进行变现就比较麻烦,…

如果这时你还不清理C盘,那只能眼睁睁看着电脑越来越卡 直到系统崩溃

如果这时候你还不清理C盘&#xff0c;那只能眼睁睁看着电脑越来越卡 直到系统崩溃。很多人就是想偷懒&#xff0c;当然这是人的天性&#xff0c;明明知道自己的C盘空间就那么大&#xff0c;一天天看着C盘空间越来越小&#xff0c;还不去清理C盘。 这样的人有两种&#xff0c;一…

软件开发案例参考

前言&#xff1a;基于平台现有需求进行新功能模块开发与实现&#xff0c;以下内容为部分源码解析&#xff0c;仅提供一些思路参考&#xff0c;不予以客观指导&#xff0c;毕竟条条大路通罗马嘛&#xff1b; 语言&#xff1a;C# 工具&#xff1a;visual studio 2017/visual st…