美文网首页后端砖头
HI3861学习笔记(22)——UDP客户端

HI3861学习笔记(22)——UDP客户端

作者: Leung_ManWah | 来源:发表于2022-03-15 18:11 被阅读0次

    一、TCP与UDP优缺点

    1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。

    2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
    TCP通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。

    3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。

    4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。

    5、TCP对系统资源要求较多,UDP对系统资源要求较少。

    二、API说明

    以下 UDP 接口位于 vendor\hisi\hi3861\hi3861\third_party\lwip_sack\include\sockets.h

    业务BUILD.gn中包含路径

    include_dirs = [
            "//utils/native/lite/include",
            "//kernel/liteos_m/components/cmsis/2.0",
            "//base/iot_hardware/interfaces/kits/wifiiot_lite",
            "//foundation/communication/interfaces/kits/wifi_lite/wifiservice",
            "//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include/",
        ]
    
    • socket()
    • bind()
    • accept()
    • shutdown()
    • getpeername()
    • getsockopt()setsockopt()
    • close()
    • read()readv()write()writev()
    • recv()
    • send()sendmsg()sendto()
    • select()
    • fcntl()

    三、UDP客户端

    3.1 主要流程

    3.1.1 第一步:新建socket

    在网络编程中所需要进行的第一件事情就是创建一个socket,无论是客户端还是服务器端,都需要创建一个socket,该函数返回socket文件描述符,类似于文件描述符。socket是一个结构体,被创建在内核中。

    //在sock_fd 进行监听,在 new_fd 接收新的链接
    int sock_fd;
    
    //创建socket
    if((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        perror("create socket failed!\r\n");
        exit(1);
    }
    

    3.1.2 第二步:配置将要连接的服务器信息(端口和IP)

    按道理服务器的地址选择 255.255.255.255,意思是不指定局域网内的某一设备,局域网所有的设备如果监听了这个端口号,那么都可以收到hi3861发来的消息。但是实际好像就只能填UDP服务器的地址,而已只能发送,不能接收。

    #define UDP_PROT  8888
    
    int addr_length;
    
    //服务器的地址信息
    struct sockaddr_in send_addr;
    socklen_t addr_length = sizeof(send_addr);
    
    //初始化预连接的服务端地址
    send_addr.sin_family = AF_INET;
    send_addr.sin_port = htons(UDP_PROT);
    send_addr.sin_addr.s_addr = inet_addr("192.168.31.225");
    addr_length = sizeof(send_addr);
    

    3.1.3 第三步:发送数据

    sendto() 用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket。参数msg指向欲连线的数据内容,参数flags一般设0。

    static const char *send_data = "Hello! I'm BearPi-HM_Nano UDP Client!\r\n";
    
    //发送数据到服务远端
    sendto(sock_fd, send_data, strlen(send_data), 0, (struct sockaddr *)&send_addr, addr_length);
    

    3.1.4 第四步:接收数据

    char recvBuf[512];
    
    while (1)
    {
        bzero(recvBuf, sizeof(recvBuf));
        ...
    
        //线程休眠一段时间
        sleep(10);
    
        //接收服务端返回的字符串
        recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&send_addr, &addr_length);
        printf("%s:%d=>%s\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port), recvBuf);
    }
    

    3.2 配置SSID和密码连接WIFI创建TCP客户端

    wifi_connect.c

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    
    #include "lwip/netif.h"
    #include "lwip/netifapi.h"
    #include "lwip/ip4_addr.h"
    #include "lwip/api_shell.h"
    
    #include "cmsis_os2.h"
    #include "hos_types.h"
    #include "wifi_device.h"
    #include "wifiiot_errno.h"
    #include "ohos_init.h"
    
    #define DEF_TIMEOUT 15
    #define ONE_SECOND 1
    
    #define SELECT_WIFI_SECURITYTYPE WIFI_SEC_TYPE_PSK  
    
    static void WiFiInit(void);
    static void WaitSacnResult(void);
    static int WaitConnectResult(void);
    static void OnWifiScanStateChangedHandler(int state, int size);
    static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info);
    static void OnHotspotStaJoinHandler(StationInfo *info);
    static void OnHotspotStateChangedHandler(int state);
    static void OnHotspotStaLeaveHandler(StationInfo *info);
    
    static int g_staScanSuccess = 0;
    static int g_ConnectSuccess = 0;
    static int ssid_count = 0;
    WifiEvent g_wifiEventHandler = {0};
    WifiErrorCode error;
    
    #define SELECT_WLAN_PORT "wlan0"
    
    int WifiConnect(const char *ssid, const char *psk)
    {
        WifiScanInfo *info = NULL;
        unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
        static struct netif *g_lwip_netif = NULL;
    
        osDelay(200);
        printf("<--System Init-->\r\n");
    
        //初始化WIFI
        WiFiInit();
    
        //使能WIFI
        if (EnableWifi() != WIFI_SUCCESS)
        {
            printf("EnableWifi failed, error = %d\r\n", error);
            return -1;
        }
    
        //判断WIFI是否激活
        if (IsWifiActive() == 0)
        {
            printf("Wifi station is not actived.\r\n");
            return -1;
        }
    
        //分配空间,保存WiFi信息
        info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);
        if (info == NULL)
        {
            return -1;
        }
        //轮询查找WiFi列表
        do{
            //重置标志位
            ssid_count = 0;
            g_staScanSuccess = 0;
    
            //开始扫描
            Scan();
    
            //等待扫描结果
            WaitSacnResult();
    
            //获取扫描列表
            error = GetScanInfoList(info, &size);
    
        }while(g_staScanSuccess != 1);
        //打印WiFi列表
        printf("********************\r\n");
        for(uint8_t i = 0; i < ssid_count; i++)
        {
            printf("no:%03d, ssid:%-30s, rssi:%5d\r\n", i+1, info[i].ssid, info[i].rssi/100);
        }
        printf("********************\r\n");
        
        //连接指定的WiFi热点
        for(uint8_t i = 0; i < ssid_count; i++)
        {
            if (strcmp(ssid, info[i].ssid) == 0)
            {
                int result;
    
                printf("Select:%3d wireless, Waiting...\r\n", i+1);
    
                //拷贝要连接的热点信息
                WifiDeviceConfig select_ap_config = {0};
                strcpy(select_ap_config.ssid, info[i].ssid);
                strcpy(select_ap_config.preSharedKey, psk);
                select_ap_config.securityType = SELECT_WIFI_SECURITYTYPE;
    
                if (AddDeviceConfig(&select_ap_config, &result) == WIFI_SUCCESS)
                {
                    if (ConnectTo(result) == WIFI_SUCCESS && WaitConnectResult() == 1)
                    {
                        printf("WiFi connect succeed!\r\n");
                        g_lwip_netif = netifapi_netif_find(SELECT_WLAN_PORT);
                        break;
                    }
                }
            }
    
            if(i == ssid_count-1)
            {
                printf("ERROR: No wifi as expected\r\n");
                while(1) osDelay(100);
            }
        }
         //启动DHCP
        if (g_lwip_netif)
        {
            dhcp_start(g_lwip_netif);
            printf("begain to dhcp\r\n");
        }
    
    
        //等待DHCP
        for(;;)
        {
            if(dhcp_is_bound(g_lwip_netif) == ERR_OK)
            {
                printf("<-- DHCP state:OK -->\r\n");
    
                //打印获取到的IP信息
                netifapi_netif_common(g_lwip_netif, dhcp_clients_info_show, NULL);
                break;
            }
    
            printf("<-- DHCP state:Inprogress -->\r\n");
            osDelay(100);
        }
    
        osDelay(100);
    
        return 0;
    }
    
    static void WiFiInit(void)
    {
        printf("<--Wifi Init-->\r\n");
        g_wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedHandler;
        g_wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedHandler;
        g_wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinHandler;
        g_wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveHandler;
        g_wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedHandler;
        error = RegisterWifiEvent(&g_wifiEventHandler);
        if (error != WIFI_SUCCESS)
        {
            printf("register wifi event fail!\r\n");
        }
        else
        {
            printf("register wifi event succeed!\r\n");
        }
    }
    
    static void OnWifiScanStateChangedHandler(int state, int size)
    {
        if (size > 0)
        {
            ssid_count = size;
            g_staScanSuccess = 1;
        }
        printf("callback function for wifi scan:%d, %d\r\n", state, size);
        return;
    }
    
    static void OnWifiConnectionChangedHandler(int state, WifiLinkedInfo *info)
    {
        if (info == NULL)
        {
            printf("WifiConnectionChanged:info is null, stat is %d.\n", state);
        }
        else
        {
            if (state == WIFI_STATE_AVALIABLE)
            {
                g_ConnectSuccess = 1;
            }
            else
            {
                g_ConnectSuccess = 0;
            }
        }
    }
    
    static void OnHotspotStaJoinHandler(StationInfo *info)
    {
        (void)info;
        printf("STA join AP\n");
        return;
    }
    
    static void OnHotspotStaLeaveHandler(StationInfo *info)
    {
        (void)info;
        printf("HotspotStaLeave:info is null.\n");
        return;
    }
    
    static void OnHotspotStateChangedHandler(int state)
    {
        printf("HotspotStateChanged:state is %d.\n", state);
        return;
    }
    
    static void WaitSacnResult(void)
    {
        int scanTimeout = DEF_TIMEOUT;
        while (scanTimeout > 0)
        {
            sleep(ONE_SECOND);
            scanTimeout--;
            if (g_staScanSuccess == 1)
            {
                printf("WaitSacnResult:wait success[%d]s\n", (DEF_TIMEOUT - scanTimeout));
                break;
            }
        }
        if (scanTimeout <= 0)
        {
            printf("WaitSacnResult:timeout!\n");
        }
    }
    
    static int WaitConnectResult(void)
    {
        int ConnectTimeout = DEF_TIMEOUT;
        while (ConnectTimeout > 0)
        {
            sleep(ONE_SECOND);
            ConnectTimeout--;
            if (g_ConnectSuccess == 1)
            {
                printf("WaitConnectResult:wait success[%d]s\n", (DEF_TIMEOUT - ConnectTimeout));
                break;
            }
        }
        if (ConnectTimeout <= 0)
        {
            printf("WaitConnectResult:timeout!\n");
            return 0;
        }
    
        return 1;
    }
    

    wifi_connect.h

    #ifndef __WIFI_CONNECT_H__
    #define __WIFI_CONNECT_H__
    
    int WifiConnect(const char *ssid,const char *psk);
    
    #endif /* __WIFI_CONNECT_H__ */
    

    四、完整代码

    编译时在业务BUILD.gn中包含路径

    static_library("myapp") {
        sources = [
            "wifi_connect.c",
            "hello_world.c"
        ]
        cflags = [ "-Wno-unused-variable" ]
        cflags += [ "-Wno-unused-but-set-variable" ]
        cflags += [ "-Wno-unused-parameter" ]
        include_dirs = [
            "//utils/native/lite/include",
            "//kernel/liteos_m/components/cmsis/2.0",
            "//base/iot_hardware/interfaces/kits/wifiiot_lite",
            "//foundation/communication/interfaces/kits/wifi_lite/wifiservice",
            "//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include/",
        ]
    }
    

    hello_world.c

    #include <stdio.h>
    #include <unistd.h>
    
    #include "ohos_init.h"
    #include "cmsis_os2.h"
    
    #include "wifi_device.h"
    #include "lwip/netifapi.h"
    #include "lwip/api_shell.h"
    #include <netdb.h>
    #include <string.h>
    #include <stdlib.h>
    #include "lwip/sockets.h"
    #include "wifi_connect.h"
    
    #define UDP_PROT 3333
    
    //在sock_fd 进行监听,在 new_fd 接收新的链接
    int sock_fd;
    
    int addr_length;
    static const char *send_data = "Hello! I'm BearPi-HM_Nano UDP Client!\r\n";
    
    //服务器的地址信息
    struct sockaddr_in send_addr;
    
    static void UDPClientTask(void)
    {
        socklen_t addr_length = sizeof(send_addr);
        char recvBuf[512];
    
        //连接Wifi
        WifiConnect("406", "82069909");
    
        //创建socket
        if ((sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) == -1)
        {
            perror("create socket failed!\r\n");
            exit(1);
        }
    
        //初始化预连接的服务端地址
        send_addr.sin_family = AF_INET;
        send_addr.sin_port = htons(UDP_PROT);
        send_addr.sin_addr.s_addr = inet_addr("192.168.31.225");
        addr_length = sizeof(send_addr);
    
        while (1)
        {
            bzero(recvBuf, sizeof(recvBuf));
    
            //发送数据到服务远端
            sendto(sock_fd, send_data, strlen(send_data), 0, (struct sockaddr *)&send_addr, addr_length);
    
            //线程休眠一段时间
            sleep(10);
    
            //接收服务端返回的字符串
            recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&send_addr, &addr_length);
            printf("%s:%d=>%s\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port), recvBuf);
        }
    
        //关闭这个 socket
        closesocket(sock_fd);
    }
    
    static void UDPClientDemo(void)
    {
        osThreadAttr_t attr;
    
        attr.name = "UDPClientTask";
        attr.attr_bits = 0U;
        attr.cb_mem = NULL;
        attr.cb_size = 0U;
        attr.stack_mem = NULL;
        attr.stack_size = 10240;
        attr.priority = osPriorityNormal;
    
        if (osThreadNew((osThreadFunc_t)UDPClientTask, NULL, &attr) == NULL)
        {
            printf("[UDPClientDemo] Falied to create UDPClientTask!\n");
        }
    }
    
    APP_FEATURE_INIT(UDPClientDemo);
    

    查看打印:



    • 由 Leung 写于 2022 年 3 月 15 日

    • 参考:【鸿蒙2.0设备开发教程】小熊派HarmonyOS 鸿蒙·季 开发教程

    相关文章

      网友评论

        本文标题:HI3861学习笔记(22)——UDP客户端

        本文链接:https://www.haomeiwen.com/subject/baeydrtx.html