鸿蒙之接收UDP消息

493 阅读4分钟

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。

使用的技术

UDP

UDP是OSI参考模型中一种无连接的传输层协议,它主要用于不要求分组顺序到达的传输中,分组传输顺序的检查与排序由应用层完成 [4] ,提供面向事务的简单不可靠信息传送服务。UDP 协议基本上是IP协议与上层协议的接口。UDP协议适用端口分别运行在同一台设备上的多个应用程序

UDP提供了无连接通信,且不对传送数据包进行可靠性保证,适合于一次传输少量数据,UDP传输的可靠性由应用层负责。常用的UDP端口号有:53(DNS)、69(TFTP)、161(SNMP),使用UDP协议包括:TFTPSNMP、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",
    ]
}
  1. “bahuyang”:是生成静态库名称,可随意更改
  2. “led.c”:代码文件

BUILD.gn(app\BUILD.gn)

import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
    features = [
        #"startup",
        "led:bahuyang"
    ]
}

  1. 将"startup"注释,运行我们自己的文件
  2. “led”:工程目录
  3. bahuyang:静态库文件

搭建的模块

  1. WiFi模块
  2. OLED显示屏
  3. 红绿黄三色交通灯

主要代码

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数据

程序流程如下:

  1. 创建一个UDP socket句柄,以及一个变量toAd的人,并设置服务器的IP地址和端口号

  2. 使用sendto()函数向服务器发送数据

  3. 使用recvfrom()函数从服务器接受消息

  4. 使用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); } } } }