梅科尔工作室-#14天鸿蒙设备开发实战#网络应用开发笔记 原创 精华
目录
HarmonyOS网络应用开发
UDP客户端
参考:
- HarmonyOS网络应用开发—UDP客户端_哔哩哔哩_bilibili
- UDP协议详解 - 知乎 (zhihu.com)
- UDP_百度百科 (baidu.com)
- UDP协议详解 - 简书 (jianshu.com)
UDP协议相关API介绍
socket.h接口简介
这个socket.h中包含声明UDP协议相关接口函数(与UDP客户端相关api如下)。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
sendto | 通过创建的套接字将数据由指定的socket发送到远端主机 |
recvfrom | 从远端主机接收UDP数据 |
close | 关闭套接字 |
更多api可参见以下TCP服务端等几个部分,源码在vendor\hisi\hi3861\hi3861\platform\os\Huawei_LiteOS\components\lib\libc\musl\include\sys\socket.h
目录下
socket()
参数:
名字 | 描述 |
---|---|
domain | 指定协议族,也就是IP地址类型,常用的有AF_INET和AF_INET6,AF_INET表示IPv4地址,AF_INET6表示IPv6地址 |
type | 指定套接字类型(可以是SOCK_RAW、SOCK_DGRAM、SOCK_STREAM,SOCK_DGRAM值UDP协议,SOCK_STREAM指TCP协议) |
protocol | 指定要与套接字一起使用的协议,常用的有IPPROTO_TCP和IPPTOTO_UDP,也可以是0,系统会自动推演出应该使用什么协议,根据第二个参数确定 |
描述:
在网络编程中所需要进行的第一件事情就是创建一个socket,无论是客户端还是服务器端,都需要创建一个socket,该函数返回socket文件描述符,类似于文件描述符。socket是一个结构体,被创建在内核中。
sendto()
参数:
名字 | 描述 |
---|---|
s | 指定套接字文件描述符 |
msg | 指定包含要发送的消息的缓冲区 |
len | 指定要发送的消息的长度 |
flags | 指示消息传输的标志 |
to | 指定指向包含目标地址的sockaddr结构的指针 |
tolen | 指定to 结构的大小 |
描述:
sendto() 用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket。参数msg指向欲连线的数据内容,参数flags 一般设0。
recvfrom()
描述:
从指定地址接收UDP数据,此函数为阻塞接收,即如果没有接收到数据会一直阻塞程序运行。
参数:
名字 | 描述 |
---|---|
s | socket描述符 |
buf | UDP数据报缓存地址 |
len | UDP数据报长度 |
flags | 该参数一般为0 |
from | 对方地址 |
fromlen | 对方地址长度 |
UDP客户端创建流程介绍
实现UDP客户端
源码在applications\BearPi\BearPi-HM_Nano\sample\D3_iot_udp_client\udp_client_demo.c
路径下,以下添加了部分注释
其中WifiConnect()
驱动会放于附件中,其中的代码逻辑可参考上篇博客梅科尔工作室-#14天鸿蒙设备开发实战#无线联网开发笔记-开源基础软件社区-51CTO.COMWiFi STA联网部分
其中的_PROT_
指定了端口号为8888,后续创建UDP服务端的时候需要用到,可以自行修改,在0-65535之间即可
获取电脑的IPv4地址的方式是,打开命令行工具,输入ipconfig
,读取ip,无线局域网适配器 WLAN下的IPv4 地址
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定udp_client
,编译、烧录
测试UDP客户端
使用Sockettool创建UDP服务端用于测试,工具会放在附件中,也可自行下载
Sockettool工具下载地址:百度网盘 请输入提取码 (baidu.com),提取码为1234
代码烧录到开发板中之后,打开TCP UDP Socket调试工具.exe文件,打开后界面如下
之后创建UDP服务端,如图所示步骤
创建完成后为以下界面,可以在此处接收到开发板发过来的数据,以及向开发板发送数据
打开MobaXterm的串口工具,按一下开发板的复位按键,此时可以看到日志中打印了一些信息,也已经可以在调试工具数据接收及提示窗口中看到开发板发送的数据;在调试工具数据发送窗口中发送数据后,可以在MobaXterm的串口工具中看到UDP服务端发送的数据。
日志结果如下:
调试工具中信息如下:
TCP服务端
参考:
- HarmonyOS网络应用开发—TCP服务端_哔哩哔哩_bilibili
- TCP(传输控制协议)_百度百科 (baidu.com)
- TCP协议详解 - 知乎 (zhihu.com)
- TCP和UDP的区别 - 知乎 (zhihu.com)
- TCP网络编程中connect()、listen()和accept()三者之间的关系 ( 非常重要!!) - 腾讯云开发者社区-腾讯云 (tencent.com)
TCP协议相关API介绍
这个socket.h中包含声明TCP协议相关接口函数(与TCP服务端相关api如下)。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
bind | 为套接字关联了一个相应的地址与端口号 |
listen | 将套接字设置为监听模式 |
accept | 接受套接字上新的连接 |
recv | 接收数据 |
send | 发送数据 |
close | 关闭套接字 |
源码在vendor\hisi\hi3861\hi3861\platform\os\Huawei_LiteOS\components\lib\libc\musl\include\sys\socket.h
路径下
bind()
参数:
名字 | 描述 |
---|---|
s | 指定要绑定的套接字的文件描述符 |
name | 指向包含要绑定到套接字的地址的sockaddr结构,地址的长度和格式取决于套接字的地址族。 |
namelen | 指定地址参数指向的sockaddr结构的长度 |
描述:
把一个本地协议地址和套接口绑定,比如把本机的2222端口绑定到套接口。注意:为什么在上部分中UDP客户端不需要调用bind函数?这是因为如果没有调用bind函数绑定一个端口的话,当调用connect函数时,内核会为该套接口临时选定一个端口,因此可以不用绑定。而服务器之所以需要绑定的原因就是,所有客户端都需要知道服务器使用的哪个端口,所以需要提前绑定。
listen()
参数:
名字 | 内容 |
---|---|
s | 指定引用SOCK_STREAM类型套接字的文件描述符 |
backlog | 定义“s”的挂起连接队列可能增长到的最大长度 |
描述:
当socket创建后,它通常被默认为是主动套接口,也就是说是默认为要马上调用connect函数的,而作为服务器是需要被动接受的,所以需要调用linsten函数将主动套接口转换成被动套接口。调用linsten函数后,内核将从该套接口接收连接请求。
accept()
描述:
此函数返回已经握手完成的连接的套接口。注意:此处的套接口不同于服务器开始创建的监听套接口,此套接口是已经完成连接的套接口,监听套接口只是用来监听。
recv()
描述:
recv函数用来从TCP连接的另一端接收数据。此函数为阻塞接收,即如果没有接收到数据会一直阻塞程序运行。
send()
描述:
send函数用来向TCP连接的另一端发送数据。
TCP服务端创建流程介绍
实现TCP服务端
源码在applications\BearPi\BearPi-HM_Nano\sample\D3_iot_udp_client\udp_client_demo.c
路径下,以下添加了部分注释
其中的_PROT_
指定了端口号为8888,后续创建TCP客户端的时候需要用到,可以自行修改,在0-65535之间即可
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定tcp_server
,编译、烧录
测试TCP服务端
代码烧录完成后,打开MobaXterm的串口工具,按一下开发板复位按键,可以看到日志中打印出开发板ip等信息(ip地址后续会用到),打开TCP UDP Socket调试工具,创建TCP客户端
创建客户端之后,点击连接,可以看到日志中打印出了accept addr
,通过调试工具数据发送窗口向开发板TCP服务端发送一些数据,发送后数据会在日志中被打印出来,在调试工具数据接收及提示窗口中也可以看到开发板TCP服务端回复的数据。
日志结果如下:
调试工具中信息如下:
TCP客户端
参考:
TCP协议相关API介绍
socket.h接口简介
这个socket.h中包含声明TCP协议相关接口函数(与TCP客户端相关api如下)。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
connect | 连接到指定的主机 |
send | 发送数据 |
recv | 接收数据 |
close | 关闭套接字 |
源码在vendor\hisi\hi3861\hi3861\platform\os\Huawei_LiteOS\components\lib\libc\musl\include\sys\socket.h
路径下
connect()
参数:
名字 | 描述 |
---|---|
s | 指定套接字文件描述符 |
name | 指定指向标识连接的sockaddr结构的指针 |
namelen | 指定name 的大小 |
描述:
此API将文件描述符s
引用的套接字连接到名称指定的地址。
TCP客户端创建流程介绍
实现TCP客户端
代码是在UDP客户端案例的基础上进行修改的,UDP客户端案例在applications\BearPi\BearPi-HM_Nano\sample\D3_iot_udp_client\udp_client_demo.c
路径下
与UDP客户端不同的是,收发数据之前需要先通过connect()
api与服务端建立连接,另外就是一些api功能相近,但是名称有些许差别,如send()
与sendto()
、recv
与recvfrom
,因为TCP客户端已经与服务端建立连接,所以使用send()
和recv
时无需再指定服务端。
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定udp_client
,编译、烧录
测试TCP客户端
打开TCP UDP Socket调试工具,创建TCP服务端
打开MobaXterm的串口工具,按一下开发板的复位按键,日志中会打印对应的信息,并且在调试工具数据接收及提示窗口中看到开发板发送的数据;在调试工具数据发送窗口中发送数据后,可以在MobaXterm的串口工具中看到TCP服务端发送的数据。
结果如下:
UDP服务端
参考:
UDP协议相关API介绍
socket.h接口简介
这个socket.h中包含声明TCP协议相关接口函数(与TCP客户端相关api如下)。
接口名 | 功能描述 |
---|---|
socket | 创建套接字 |
bind | 将ip和端口绑定到嵌套字 |
sendto | 将数据由指定的socket发送对方主机 |
recvfrom | 从指定主机接收UDP数据 |
close | 关闭套接字 |
源码在vendor\hisi\hi3861\hi3861\platform\os\Huawei_LiteOS\components\lib\libc\musl\include\sys\socket.h
路径下
UDP服务端创建流程介绍
实现UDP服务端
代码是在TCP服务端案例的基础上进行修改的,TCP服务端案例源码在applications\BearPi\BearPi-HM_Nano\sample\D3_iot_udp_client\udp_client_demo.c
路径下
与TCP服务端相比,UDP不需要使用listen()
api对服务器进行监听,也不再需要accept
api来提取挂起连接队列上的第一个连接请求,且两者进行数据收发所使用的api也不同,UDP使用recvfrom
和sendto
,TCP使用的是recv
和send
。
其中的_PROT_
指定了端口号为8888,后续创建UDP客户端的时候需要用到,可以自行修改,在0-65535之间即可
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定tcp_server
,编译、烧录
测试UDP服务端
代码烧录完成后,打开MobaXterm的串口工具,按一下开发板复位按键,可以看到日志中打印出开发板联网成功信息、ip等信息(ip地址后续将会用到),打开TCP UDP Socket调试工具,创建UDP客户端
当通过调试工具中的数据发送窗口向开发板的UDP服务端发送数据后,在数据接收及提示窗口可以看到开发板服务端的数据反馈,并且在串口工具打印的日志中,也可以看到UDP客户端发送过来的数据。
结果如下:
MQTT客户端
参考:
- HarmonyOS网络应用开发—MQTT客户端_哔哩哔哩_bilibili
- MQTT_百度百科 (baidu.com)
- MQTT 入门介绍 | 菜鸟教程 (runoob.com)
- MQTT · OneOS开发者文档 (10086.cn)
- HI3861学习笔记(24)——MQTT客户端 - 简书 (jianshu.com)
- MQTT协议,终于有人讲清楚了 - 知乎 (zhihu.com)
MQTT介绍
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。
Paho是IBM在2011年建立的Eclipse开源项目,该项目包含以C、Java、Python、Javascript等语言编写的可用客户端。
本次使用的是C语言编写的客户端,开源地址是:eclipse/paho.mqtt.embedded-c: Paho MQTT C client library for embedded systems. Paho is an Eclipse IoT project (https://iot.eclipse.org/) (github.com),下载下来的源码会放在附件。
Paho MQTT 文件目录介绍
打开下载下来的源码,或者直接在GitHub上打开,
其中比较重要的3个文件夹是:
- MQTTClient:封装MQTTPacket生成的高级别C++客户端程序。
- MQTTClient-C: 封装MQTTPacket生成的高级别C客户端程序
- samples目录提供FreeRTOS和linux两个例程,分别支持FreeRTOS和Linux系统。
- src目录提供MQTTClient的代码实现能力,以及用于移植到对应平台的网络驱动
- MQTTPacket:提供MQTT数据包的序列化与反序列化,以及部分辅助函数。
MQTTClient-C\src
路径下的MQTTClient.h中包含了供开发者使用的api接口,具体见下。
从hpm官网或者gitee仓库下载的源码中,已经包含了Paho MQTT,路径为third_party\paho_mqtt
如何使用Paho MQTT
在MQTTClient.h中包含声明Paho MQTT相关接口函数。
接口名 | 功能描述 |
---|---|
MQTTClientInit | 创建一个客户端对象 |
MQTTConnect | 发送MQTT连接数据包 |
MQTTConnectWithResults | 发送MQTT连接数据包并等待返回 |
MQTTPublish | 发送MQTT发布数据包 |
MQTTSetMessageHandler | 发送每个topic消息处理函数 |
MQTTSubscribe | 发送MQTT订阅数据包 |
MQTTSubscribeWithResults | 发送MQTT订阅数据包并等待返回结果 |
MQTTUnsubscribe | 发送MQTT取消数据包 |
MQTTDisconnect | 发送MQTT断开连接数据包并关闭连接 |
源码在上文提到的MQTTClient-C\src\MQTTClient.h
路径下。但是解释的不够具体。
MQTTClientInit()
参数:
名字 | 描述 |
---|---|
client | 指向需要初始化的MQTT客户端结构体 |
network | 指向需要初始化的MQTT客户端的网络结构体 |
command_timeout_ms | 命令执行超时时间 |
sendbuf | 客户端发送数据缓冲区地址 |
sendbuf_size | 发送数据缓冲区容量 |
readbuf | 客户端接收数据缓冲区地址 |
readbuf_size | 接收数据缓冲区容量 |
描述:
创建一个MQTT客户端对象
MQTTConnect()
参数:
名字 | 描述 |
---|---|
client | 客户端结构体指针 |
options | 连接选项结构体指针 |
返回值:
返回值 | 描述 |
---|---|
int | =0初始化成功;<0初始化失败 |
描述:
在网络上发送MQTT connect数据包并等待Connack。在调用此数据包之前,必须将nework对象连接到网络端点。
MQTTConnectWithResults()
参数:
名字 | 描述 |
---|---|
client | 客户端结构体指针 |
options | 连接选项结构体指针 |
data | MQTT Connack数据 |
描述:
在网络上发送MQTT connect数据包并等待Connack。在调用此数据包之前,必须将nework对象连接到网络端点。
MQTTPublish()
参数:
名字 | 描述 |
---|---|
client | 指向需要发布消息的客户端结构体 |
topicName | 指向需要发布的消息主题 |
message | 指向需要发布的消息结构体 |
描述:
用于发布MQTT消息,发送MQTT发布数据包,并等待所有QoS的所有ACK完成。
MQTTSubscribe()
参数:
名字 | 描述 |
---|---|
client | 指向需要订阅消息的客户端结构体 |
topicFilter | 指向需要订阅的消息主题 |
QoS | 订阅消息的服务质量 |
messageHandler | 指向订阅消息的回调函数 |
返回值:
返回值 | 描述 |
---|---|
int | =0初始化成功;<0初始化失败 |
描述:
实现MQTT消息订阅,发送MQTT subscribe数据包并等待suback,然后返回。
实现MQTT客户端
源码在applications\BearPi\BearPi-HM_Nano\sample\D5_iot_mqtt\iot_mqtt.c
路径下,以下添加了部分注释
其中订阅的消息主题名称是substopic
,发布的消息主题名称是pubtopic
,后续还会再用到
测试MQTT客户端
工具下载安装及配置
首先需要下载两个工具,会放在附件中,也可自行下载,下载路径在后面。
MQTT消息代理软件mosquitto
下载地址:Download | Eclipse Mosquitto
根据自己的电脑选择相应的版本,本人是64位win10电脑,选择下载64位的windows版
下载完成后双击进行安装,过程较为简单,不再赘述。
安装完成之后需要修改它的配置文件,首先打开它的安装位置,找到mosquitto.conf文件并打开
- 搜索
allow_anonymous false
,将它的注释打开,并将false
改为true
- 搜索
listener
(230行左右,listener个数较多供参考),将它的注释打开,并在后面加上(有一个空格)1883 电脑ip
(电脑ip需要自行查找),另起一行加上listener 1883 localhost
,保存文件
修改完成
之后启动此服务,打开任务管理器,选择服务,右键再点击开始以启动服务。
Eclipse桌面客户端程序
下载地址:Index of /repositories/paho-releases/org/eclipse/paho/org.eclipse.paho.ui.app/1.1.1
同样需要根据自己的电脑选择相应的版本,我选择windows64位的版本
下载完成后解压,无需安装,双击paho.exe应用程序打开
测试
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定iot_mqtt
,编译、烧录
订阅功能测试
在eclipse工具中添加订阅,
之后使用MobaXterm的串口工具,点击开发板复位按键,等待串口工具打印出开始订阅的日志,之后如果在eclipse工具中的历史记录中可以看到开发板发过来的数据,说明客户端已经订阅到了开发板发布的数据,客户端的订阅功能没有问题,开发板发布功能没有问题。
发布功能测试
在eclipse工具中发布一个主题,
如果在MobaXterm的串口工具日志中打印出了发布内容,则证明客户端的发布能没有问题,开发板订阅功能没有问题。
本章所用到的案例源码及相关工具见附件。
感悟
学习完本章后学习最大的感觉就是有些抽象,是之前学习过的几章中最不好理解的一部分,首先是TCP、UDP的原理不太了解,其次是里面的一些基本概念不懂,再次让我体会到了打牢基础的重要性(小白落泪)。另外在初学阶段,不能太深究底层的东西,比如里面设计到的api,我们只需要知道有什么功能,需要哪些参数,怎么去用就可以了,具体的原理不需要深入探究(而且以我目前的水平也无能为力),既然是想短时间内学习某种技术,那么实践才是最重要的。最后一章,加油!!!
UDP和TCP可以说是通信的必经之路了
另外楼主可以考虑开个专栏(https://ost.51cto.com/column)统一收录下自己的文章。