「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。
使用的技术
UDP
UDP是OSI参考模型中一种无连接的传输层协议,它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成 [4] ,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP协议与上层协议的接口。UDP协议适用端口分别运行在同一台设备上的多个应用程序。
UDP提供了无连接通信,且不对传送数据包进行可靠性保证,适合于一次传输少量数据,UDP传输的可靠性由应用层负责。常用的UDP端口号有:53(DNS)、69(TFTP)、161(SNMP),使用UDP协议包括:TFTP、SNMP、NFS、DNS、BOOTP。
UDP报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。但是正因为UDP协议的控制选项较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序,如DNS、TFTP、SNMP等。
方法
说明
Close
关闭 UDP 连接
Connect
建立与远程主机的连接
DropMulticastGroup
退出多路广播组
JoinMulticastGroup
将 UdpClient 添加到多路广播组
Receive
返回已由远程主机发送的 UDP 数据文报
Send
将 UDP 数据文报发送到远程主机
JSON
JSON介绍
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。
JSON是Douglas Crockford在2001年开始推广使用的数据格式,在2005年-2006年正式成为主流的数据格式,雅虎和谷歌就在那时候开始广泛地使用JSON格式。
具体设计
文件结构
先在./applications/sample/wifi-iot/app路径下新建一个目录(或一套目录结构),用于存放业务源码文件。
本例程:在app下新增业务led,其中hello_world.c为业务代码,BUILD.gn为编译脚本,具体规划目录结构如下:
└── applications
└── sample
└── wifi-iot
└── app
│── led
│ │── led.c
│ └── BUILD.gn
└── BUILD.gn
功能实现
新建./applications/sample/wifi-iot/app/led下的led.c文件,在led.c中新建业务入口函数led,并实现业务逻辑。并在代码最下方,使用HarmonyOS启动恢复模块接口SYS_RUN()启动业务。(SYS_RUN定义在ohos_init.h文件中)
BUILD.gn为编译脚本
led.c为业务逻辑代码所在文件
BUILD.gn(app/led/BUILD.gn)
static_library("bahuyang") {
sources = [
"led.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
"//base/iot_hardware/interfaces/kits/wifiiot_lite",
]
}
- “bahuyang”:是生成静态库名称,可随意更改
- “led.c”:代码文件
BUILD.gn(app\BUILD.gn)
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
#"startup",
"led:bahuyang"
]
}
- 将"startup"注释,运行我们自己的文件
- “led”:工程目录
- bahuyang:静态库文件
搭建的模块
- WiFi模块
- OLED显示屏
- 红绿黄三色交通灯
主要代码
sta联网
int hi_wifi_start_connect(void)
{
int ret;
errno_t rc;
hi_wifi_assoc_request assoc_req = {0};
/* copy SSID to assoc_req */
//热点名称
rc = memcpy_s(assoc_req.ssid, HI_WIFI_MAX_SSID_LEN + 1, "BAHUYANG", 8); /* 9:ssid length */
if (rc != EOK) {
printf("%s %d \r\n", __FILE__, __LINE__);
return -1;
}
/*
* OPEN mode
* for WPA2-PSK mode:
* set assoc_req.auth as HI_WIFI_SECURITY_WPA2PSK,
* then memcpy(assoc_req.key, "12345678", 8).
*/
//热点加密方式
assoc_req.auth = HI_WIFI_SECURITY_WPA2PSK;
/* 热点密码 */
memcpy(assoc_req.key, "123456789", 9);
ret = hi_wifi_sta_connect(&assoc_req);
if (ret != HISI_OK) {
printf("%s %d \r\n", __FILE__, __LINE__);
return -1;
}
printf("%s %d \r\n", __FILE__, __LINE__);
return 0;
}
int hi_wifi_start_sta(void)
{
int ret;
char ifname[WIFI_IFNAME_MAX_SIZE + 1] = {0};
int len = sizeof(ifname);
const unsigned char wifi_vap_res_num = APP_INIT_VAP_NUM;
const unsigned char wifi_user_res_num = APP_INIT_USR_NUM;
printf("%s %d \r\n", __FILE__, __LINE__);
ret = hi_wifi_init(wifi_vap_res_num, wifi_user_res_num);
if (ret != HISI_OK) {
printf("%s %d \r\n", __FILE__, __LINE__);
//return -1;
}
printf("%s %d \r\n", __FILE__, __LINE__);
ret = hi_wifi_sta_start(ifname, &len);
if (ret != HISI_OK) {
printf("%s %d \r\n", __FILE__, __LINE__);
return -1;
}
接收UDP数据
程序流程如下:
-
创建一个UDP socket句柄,以及一个变量toAd的人,并设置服务器的IP地址和端口号
-
使用sendto()函数向服务器发送数据
-
使用recvfrom()函数从服务器接受消息
-
使用close()函数关闭此socket
char recvline[1024]; void udp_thread(void *pdata) { int ret; struct sockaddr_in servaddr; cJSON recvjson; pdata = pdata; int sockfd = socket(PF_INET, SOCK_DGRAM, 0); //服务器 ip port bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(50001); printf("udp_thread \r\n"); bind(sockfd, (struct sockaddr )&servaddr, sizeof(servaddr)); while(1) { struct sockaddr_in addrClient; int sizeClientAddr = sizeof(struct sockaddr_in); memset(recvline, sizeof(recvline), 0); ret = recvfrom(sockfd, recvline, 1024, 0, (struct sockaddr)&addrClient,(socklen_t)&sizeClientAddr); if(ret>0) { char *pClientIP =inet_ntoa(addrClient.sin_addr); printf("%s-%d(%d) says:%s\n",pClientIP,ntohs(addrClient.sin_port),addrClient.sin_port, recvline); //进行json解析 recvjson = cJSON_Parse(recvline); if(recvjson != NULL) { if(cJSON_GetObjectItem(recvjson, "cmd")->valuestring != NULL) { printf("cmd : %s\r\n", cJSON_GetObjectItem(recvjson, "cmd")->valuestring); if(strcmp("RED", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0) { set_LED_status(LED_STATUS_RED); printf("RED\r\n"); } if(strcmp("YELLOW", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0) { set_LED_status(LED_STATUS_YELLOW); printf("YELLOW\r\n"); } if(strcmp("GREEN", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0) { set_LED_status(LED_STATUS_GREEN); printf("GREEN\r\n"); } if(strcmp("CLOSE", cJSON_GetObjectItem(recvjson, "cmd")->valuestring) == 0) { set_LED_status(LED_STATUS_CLOSE); printf("CLOSE\r\n"); } }
cJSON_Delete(recvjson); } } } }