HarmonyOS NEXT开发系列(5.0版)UDP协议通讯实践

打印 上一主题 下一主题

主题 1031|帖子 1031|积分 3093

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
鸿蒙NEXT开发实战往期必看文章:

HarmonyOS NEXT应用开发案例实践总联合(持续更新......)
HarmonyOS NEXT应用开发性能优化实践总结(持续更新......)
一分钟相识”纯血版!鸿蒙HarmonyOS Next应用开发!
“非常详细的” 鸿蒙HarmonyOS Next应用开发学习路线!(从零基础入门到精通)

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协议发送、接收消息的功能,运行后的界面如下所示:


下面详细先容创建该应用的步骤。
步骤1:创建Empty Ability项目。
步骤2:在module.json5配置文件加上对权限的声明:
   "requestPermissions": [
        {
          "name": "ohos.permission.INTERNET"
        },
        {
          "name": "ohos.permission.GET_WIFI_INFO"
        }
      ]
  这里分别添加了访问互联网和访问WIFI信息的权限。
步骤3:在Index.ets文件里添加如下的代码:
  1. import socket from '@ohos.net.socket';
  2. import wifiManager from '@ohos.wifiManager';
  3. import systemDateTime from '@ohos.systemDateTime';
  4. import util from '@ohos.util';
  5. //执行UDP通讯的对象
  6. let udpSocket = socket.constructUDPSocketInstance();
  7. //说明:本地的IP地址不是必须知道的,绑定时绑定到IP:0.0.0.0即可,显示本地IP地址的目的是方便对方发送信息过来
  8. //本地IP的数值形式
  9. let ipNum = wifiManager.getIpInfo().ipAddress
  10. //本地IP的字符串形式
  11. let localIp = (ipNum >>> 24) + '.' + (ipNum >> 16 & 0xFF) + '.' + (ipNum >> 8 & 0xFF) + '.' + (ipNum & 0xFF);
  12. @Entry
  13. @Component
  14. struct Index {
  15.   //连接、通讯历史记录
  16.   @State msgHistory: string = ''
  17.   //要发送的信息
  18.   @State sendMsg: string = ''
  19.   //本地端口
  20.   @State localPort: number = 9990
  21.   //目的IP地址
  22.   @State targetIp: string = "0.0.0.0"
  23.   //目的端口
  24.   @State targetPort: number = 9990
  25.   scroller: Scroller = new Scroller()
  26.   build() {
  27.     Row() {
  28.       Column() {
  29.         Text("UDP通讯示例")
  30.           .fontSize(14)
  31.           .fontWeight(FontWeight.Bold)
  32.           .width('100%')
  33.           .textAlign(TextAlign.Center)
  34.           .padding(10)
  35.         Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
  36.           Text("本地IP和端口:")
  37.             .width(110)
  38.             .fontSize(14)
  39.             .flexGrow(0)
  40.           Text(localIp)
  41.             .width(80)
  42.             .fontSize(14)
  43.             .flexGrow(0)
  44.           TextInput({ text: this.localPort.toString() })
  45.             .type(InputType.Number)
  46.             .onChange((value) => {
  47.               this.localPort = parseInt(value)
  48.             })
  49.             .width(100)
  50.             .flexGrow(3)
  51.           Button("绑定")
  52.             .onClick(() => {
  53.               this.bind2Port()
  54.             })
  55.             .width(80)
  56.             .fontSize(14)
  57.             .flexGrow(0)
  58.         }.width('100%')
  59.         .padding(10)
  60.         Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
  61.           Text("对端IP和端口:")
  62.             .fontSize(14)
  63.             .width(110)
  64.             .flexGrow(1)
  65.           TextInput({ text: this.targetIp })
  66.             .onChange((value) => {
  67.               this.targetIp = value
  68.             })
  69.             .width(100)
  70.             .flexGrow(4)
  71.           Text(":")
  72.             .width(5)
  73.             .flexGrow(0)
  74.           TextInput({ text: this.targetPort.toString() })
  75.             .type(InputType.Number)
  76.             .onChange((value) => {
  77.               this.targetPort = parseInt(value)
  78.             })
  79.             .flexGrow(2)
  80.             .width(60)
  81.         }
  82.         .width('100%')
  83.         .padding(10)
  84.         Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
  85.           TextInput({ placeholder: "输入要发送的消息" }).onChange((value) => {
  86.             this.sendMsg = value
  87.           })
  88.             .width(200)
  89.             .flexGrow(1)
  90.           Button("发送")
  91.             .width(80)
  92.             .flexGrow(0)
  93.             .onClick(() => {
  94.               this.sendMsg2Target()
  95.             })
  96.         }
  97.         .width('100%')
  98.         .padding(10)
  99.         Scroll(this.scroller) {
  100.           Text(this.msgHistory)
  101.             .textAlign(TextAlign.Start)
  102.             .padding(10)
  103.             .width('100%')
  104.             .backgroundColor(0xeeeeee)
  105.         }
  106.         .align(Alignment.Top)
  107.         .backgroundColor(0xeeeeee)
  108.         .height(300)
  109.         .flexGrow(1)
  110.         .scrollable(ScrollDirection.Vertical)
  111.         .scrollBar(BarState.On)
  112.         .scrollBarWidth(20)
  113.       }
  114.       .width('100%')
  115.       .justifyContent(FlexAlign.Start)
  116.       .height('100%')
  117.     }
  118.     .height('100%')
  119.   }
  120.   //发送消息到目的ip和端口
  121.   sendMsg2Target() {
  122.     //目的ip和端口
  123.     let remoteAddress = { address: this.targetIp, port: this.targetPort, family: 1 }
  124.     udpSocket.send({ data: this.sendMsg, address: remoteAddress })
  125.       .then(async () => {
  126.         this.msgHistory += "我:" + this.sendMsg + await getCurrentTimeString() + "\r\n"
  127.       })
  128.       .catch((e) => {
  129.         this.msgHistory += '发送失败' + e.message + "\r\n";
  130.       })
  131.   }
  132.   //绑定本地端口
  133.   async bind2Port() {
  134.     //本地地址
  135.     let localAddress = { address: "0.0.0.0", port: this.localPort, family: 1 }
  136.     await udpSocket.bind(localAddress)
  137.       .then(() => {
  138.         this.msgHistory = 'bind success' + "\r\n";
  139.       })
  140.       .catch((e) => {
  141.         this.msgHistory = 'bind fail' + e.message + "\r\n";
  142.       })
  143.     //收到消息时的处理
  144.     udpSocket.on("message", async (value) => {
  145.       let msg = buf2String(value.message)
  146.       let remoteIP = value.remoteInfo.address
  147.       let remotePort = value.remoteInfo.port.toString()
  148.       //对端ip地址和端口的字符串形式
  149.       let remoteAddr = "[" + remoteIP + ":" + remotePort + "]:"
  150.       let time = await getCurrentTimeString()
  151.       this.msgHistory += remoteAddr + msg + time + "\r\n"
  152.       this.scroller.scrollEdge(Edge.Bottom)
  153.     })
  154.   }
  155. }
  156. //同步获取当前时间的字符串形式
  157. async function getCurrentTimeString() {
  158.   let time = ""
  159.   await  systemDateTime.getDate().then(
  160.     (date) => {
  161.       time = date.getHours().toString() + ":" + date.getMinutes().toString()
  162.       + ":" + date.getSeconds().toString()
  163.     }
  164.   )
  165.   return "[" + time + "]"
  166. }
  167. //ArrayBuffer转utf8字符串
  168. function buf2String(buf: ArrayBuffer) {
  169.   let msgArray = new Uint8Array(buf);
  170.   let textDecoder = util.TextDecoder.create("utf-8");
  171.   return textDecoder.decodeWithStream(msgArray)
  172. }
复制代码
步骤4:编译运行。如果通过模拟器来部署运行,需要使用长途模拟器


使用本地模拟器可能会有网络题目。
另外,使用模拟器的时候要确保打开WIFI,可以通过设置->WLAN页面开启。
步骤5:配置本地端口和对端IP地址和端口,然后单击绑定按钮绑定到本地指定的端口,再单击发送按钮发送消息。可以根据实际需要配置,如果没有对端的UDP应用,把本应用作为对端也可以,也就是相当于本身给本身发送消息,末了本身再接收,如图所示:


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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

乌市泽哥

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表