HarmonyOS小熊派 | HarmonyOS WiFi编程开发--UDP服务端

举报
Yuchuan 发表于 2021/09/01 19:43:18 2021/09/01
【摘要】 本示例将演示如何在BearPi-HM_Nano开发板上使用socket编程创建UDP服务端,接收客户端消息并回复固定消息。

BearPi-HM_Nano开发板WiFi编程开发——UDP服务端

本示例将演示如何在BearPi-HM_Nano开发板上使用socket编程创建UDP服务端,接收客户端消息并回复固定消息。

BearPi-HM_Nano

socket.h接口简介:
这个socket.h中包含声明UDP协议相关接口函数。

 

socket API分析

本案例主要使用了以下几个API完socket编程实验

1、socket()

sock_fd = socket(AF_INET, SOCK_STREAM, 0)) //AF_INT:ipv4, SOCK_STREAM:tcp协议
NAME
       socket - create an endpoint for communication

SYNOPSIS
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       int socket(int domain, int type, int protocol);

DESCRIPTION
       socket() creates an endpoint for communication and returns a file descriptor that refers to that endpoint.  The file descriptor returned by a successful call will
       be the lowest-numbered file descriptor not currently open for the process.

       The domain argument specifies a communication domain; this selects the protocol family which will be used  for  communication.   These  families  are  defined  in
       <sys/socket.h>.  The formats currently understood by the Linux kernel include:

描述:

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

2、bind()

bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))
NAME
       bind - bind a name to a socket

SYNOPSIS
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);

DESCRIPTION
       When  a  socket  is created with socket(2), it exists in a name space (address family) but has no address assigned to it.  bind() assigns the address specified by
       addr to the socket referred to by the file descriptor sockfd.  addrlen specifies the size, in bytes, of the address structure pointed to by addr.   Traditionally,
       this operation is called “assigning a name to a socket”.

       It is normally necessary to assign a local address using bind() before a SOCK_STREAM socket may receive connections (see accept(2)).

       The  rules  used  in  name  binding vary between address families.  Consult the manual entries in Section 7 for detailed information.  For AF_INET, see ip(7); for
       AF_INET6, see ipv6(7); for AF_UNIX, see unix(7); for AF_APPLETALK, see ddp(7); for AF_PACKET, see packet(7); for AF_X25,  see  x25(7);  and  for  AF_NETLINK,  see
       netlink(7).

       The actual structure passed for the addr argument will depend on the address family.  The sockaddr structure is defined as something like:

           struct sockaddr {
               sa_family_t sa_family;
               char        sa_data[14];
           }

       The only purpose of this structure is to cast the structure pointer passed in addr in order to avoid compiler warnings.  See EXAMPLE below.

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

描述:

把一个本地协议地址和套接口绑定,比如把本机的2222端口绑定到套接口。注意:为什么在上图中客户端不需要调用bind函数?这是因为如果没有调用bind函数绑定一个端口的话,当调用connect函数时,内核会为该套接口临时选定一个端口,因此可以不用绑定。而服务器之所以需要绑定的原因就是,所以客户端都需要知道服务器使用的哪个端口,所以需要提前绑定

3、recvfrom()

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
NAME
       recv, recvfrom, recvmsg - receive a message from a socket

SYNOPSIS
       #include <sys/types.h>
       #include <sys/socket.h>

       ssize_t recv(int sockfd, void *buf, size_t len, int flags);

       ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

       ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

DESCRIPTION
       The  recv(),  recvfrom(), and recvmsg() calls are used to receive messages from a socket.  They may be used to
       receive data on both connectionless and connection-oriented sockets.  This page first  describes  common  fea‐
       tures of all three system calls, and then describes the differences between the calls.

       The  only  difference between recv() and read(2) is the presence of flags.  With a zero flags argument, recv()
       is generally equivalent to read(2) (but see NOTES).  Also, the following call

           recv(sockfd, buf, len, flags);

       is equivalent to

           recvfrom(sockfd, buf, len, flags, NULL, NULL);

       All three calls return the length of the message on successful completion.  If a message is too long to fit in
       the  supplied  buffer,  excess  bytes may be discarded depending on the type of socket the message is received
       from.

       If no messages are available at the socket, the receive calls wait for a message to arrive, unless the  socket
       is  nonblocking  (see fcntl(2)), in which case the value -1 is returned and the external variable errno is set
       to EAGAIN or EWOULDBLOCK.  The receive calls normally return any data available, up to the  requested  amount,
       rather than waiting for receipt of the full amount requested.

       An application can use select(2), poll(2), or epoll(7) to determine when more data arrives on a socket.

描述:

对于recvfrom()函数,成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。

4、sendto()

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
NAME
       send, sendto, sendmsg - send a message on a socket

SYNOPSIS
       #include <sys/types.h>
       #include <sys/socket.h>

       ssize_t send(int sockfd, const void *buf, size_t len, int flags);

       ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);

       ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

DESCRIPTION
       The system calls send(), sendto(), and sendmsg() are used to transmit a message to another socket.

       The  send() call may be used only when the socket is in a connected state (so that the intended recipient is known).  The only dif‐
       ference between send() and write(2) is the presence of flags.  With a zero flags argument, send() is equivalent to write(2).  Also,
       the following call

           send(sockfd, buf, len, flags);

       is equivalent to

           sendto(sockfd, buf, len, flags, NULL, 0);

       The argument sockfd is the file descriptor of the sending socket.

       If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) socket, the arguments dest_addr and addrlen are ignored (and
       the error EISCONN may be returned when they are not NULL and 0), and the error ENOTCONN is returned when the socket was  not  actu‐
       ally  connected.   Otherwise, the address of the target is given by dest_addr with addrlen specifying its size.  For sendmsg(), the
       address of the target is given by msg.msg_name, with msg.msg_namelen specifying its size.

       For send() and sendto(), the message is found in buf and has length len.  For sendmsg(), the message is pointed to by the  elements
       of the array msg.msg_iov.  The sendmsg() call also allows sending ancillary data (also known as control information).

       If  the  message is too long to pass atomically through the underlying protocol, the error EMSGSIZE is returned, and the message is
       not transmitted.

       No indication of failure to deliver is implicit in a send().  Locally detected errors are indicated by a return value of -1.

       When the message does not fit into the send buffer of the socket, send() normally blocks, unless the socket has been placed in non‐
       blocking I/O mode.  In nonblocking mode it would fail with the error EAGAIN or EWOULDBLOCK in this case.  The select(2) call may be
       used to determine when it is possible to send more data.

描述:

对于sendto()函数,成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。

5、close()

int close(int fd);
NAME
       close - close a file descriptor

SYNOPSIS
       #include <unistd.h>

       int close(int fd);

DESCRIPTION
       close()  closes a file descriptor, so that it no longer refers to any file and may be reused.  Any record locks (see fcntl(2)) held
       on the file it was associated with, and owned by the process, are removed (regardless of the file descriptor that was used  to  ob‐
       tain the lock).

       If  fd  is  the last file descriptor referring to the underlying open file description (see open(2)), the resources associated with
       the open file description are freed; if the file descriptor was the last reference to a file  which  has  been  removed  using  un‐
       link(2), the file is deleted.

RETURN VALUE
       close() returns zero on success.  On error, -1 is returned, and errno is set appropriately.

描述:

关闭socket文件描述符

软件设计

主要代码分析

完成Wifi热点的连接需要以下几步

UDP服务端创建流程介绍

项目结构目录:

yuchuan@yuchuan:~/MasterData/SharedData/MasterHarmonyOSCode/HarmonyOSCode/applications/sample/BearPi/BearPi-HM_Nano/sample/D3_YuchuanUDPServer$ tree
.
├── BUILD.gn
├── include
│   └── wifi_connect.h
├── src
│   └── wifi_connect.c
└── yuchuanUDPServer.c

2 directories, 4 files
yuchuan@yuchuan:~/MasterData/SharedData/MasterHarmonyOSCode/HarmonyOSCode/applications/sample/BearPi/BearPi-HM_Nano/sample/D3_YuchuanUDPServer$

yuchuanUDPServer.c

#include <stdio.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_connect.h"
#include "lwip/sockets.h"

#define WIFI_ACCOUNT "886699"
#define WIFI_PASSWD "te11from"
#define _PROT_ 8888

int sock_fd, new_sock_fd;

char recvBuff[512];

char *buff = "Yuchuan Huaying I'm UDP Server.\r\n";

/* UDP创建UDP任务的函数 */
static void yuchuanUDPServerTask(void)
{
    // 服务器地址信息
    struct sockaddr_in server_sock;

    // 客户端地址信息
    struct sockaddr_in client_sock;

    socklen_t sin_size;

    // 连接WiFi
    wifiConnect(WIFI_ACCOUNT, WIFI_PASSWD);

    // 创建socket
    if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        perror("Socket Is Error.\r\n");
        exit(1);
    }

    // 清理数据
    bzero(&server_sock, sizeof(server_sock));
    server_sock.sin_family = AF_INET;
    server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
    server_sock.sin_port = htons(_PROT_);

    // 调用 Bind 绑定Socket 和 地址
    if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
    {
        perror("Bind Is Error.\r\n");
        exit(1);
    }

    // 处理目标
    ssize_t ret;
    while (1)
    {
        sin_size = sizeof(struct sockaddr_in);

        while (1)
        {
            // 清理数据
            bzero(recvBuff, sizeof(recvBuff));
            if ((ret = recvfrom(sock_fd, recvBuff, sizeof(recvBuff), 0, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
            {
                printf("Recv Error.\r\n");
            }
            printf("Recv : %s.\r\n", recvBuff);

            if ((ret = sendto(new_sock_fd, buff, strlen(buff) + 1, 0, (struct sockaddr *)&client_sock, sizeof(client_sock))) == -1)
            {
                printf("Send : \r\n");
            }
        }

        close(new_sock_fd);
    }
}

/* UDP 服务的入口函数 */
static void yuchuanUDPServerEntry(void)
{
    osThreadAttr_t threadAttr;
    threadAttr.attr_bits = 0U;
    threadAttr.cb_mem = NULL;
    threadAttr.cb_size = 0U;
    threadAttr.stack_mem = NULL;
    threadAttr.stack_size = 10240;
    threadAttr.priority = 24;
    threadAttr.name = "YuchuanUDPServerTask";

    if (osThreadNew((osThreadFunc_t)yuchuanUDPServerTask, NULL, &threadAttr) == NULL)
    {
        printf("Falied To Create YuchuanUDPServerTask.\r\n");
    }
}

APP_FEATURE_INIT(yuchuanUDPServerEntry);

src/wifi_connect.c

/*
 * Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "wifi_error_code.h"

#include "lwip/api_shell.h"
#include "lwip/ip4_addr.h"
#include "lwip/netif.h"
#include "lwip/netifapi.h"

#define DEF_TIMEOUT 15
#define ONE_SECOND 1
#define SELECT_WIFI_SECURITYTYPE WIFI_SEC_TYPE_PSK
#define SELECT_WLAN_PORT "wlan0"

WifiErrorCode errorCode;
WifiEvent wifiEventHandler = {0};

static int ssid_count = 0;
static int staScanSuccess = 0;
static int staConnectSuccess = 0;

/* WiFi 站点改变扫描的回调函数 */
static void OnWifiScanStateChangedCallBack(int state, int size)
{
    if (size > 0)
    {
        ssid_count = size;
        staScanSuccess = 1;
    }
    printf("WiFi CallBack Function Is Success Scan:%d ,%d.\r\n", state, size);
    return;
}

/* WiFi 连接改变的回调函数 */
static void OnWifiConnectionChangedCallBack(int state, WifiLinkedInfo *info)
{
    if (info == NULL)
    {
        printf("OnWifiConnectionChangedCallBack: info is null state is %d.\r\n", state);
    }
    else
    {
        if (state == WIFI_STATE_AVALIABLE)
        {
            staConnectSuccess = 1;
        }
        else
        {
            staConnectSuccess = 0;
        }
    }
}

/* WiFi 加入站点的回调函数 */
static void OnHotspotStaJoinCallBack(StationInfo *info)
{
    (void)info;
    printf("OnHotspotStaJoinCallBack: Sta Join AP.\r\n");
    return;
}

/* WiFi 离开站点的回调函数 */
static void OnHotspotStaLeaveCallBack(StationInfo *info)
{
    (void)info;
    printf("OnHotspotStaLeaveCallBack: info is null.\r\n");
    return;
}

/* WiFi 状态改变的回调函数 */
static void OnHotspotStateChangedCallBack(int state)
{
    printf("OnHotspotStateChangedCallBack: state is %d.\r\n", state);
    return;
}

/* 初始化WIFI */
static void wifiInit(void)
{
    printf(">>>WiFi Init Start ......\r\n");

    /** Scan state change */
    // void (*OnWifiScanStateChanged)(int state, int size);
    wifiEventHandler.OnWifiScanStateChanged = OnWifiScanStateChangedCallBack;

    /** Connection state change */
    // void (*OnWifiConnectionChanged)(int state, WifiLinkedInfo* info);
    wifiEventHandler.OnWifiConnectionChanged = OnWifiConnectionChangedCallBack;

    /** Station connected */
    // void (*OnHotspotStaJoin)(StationInfo* info);
    wifiEventHandler.OnHotspotStaJoin = OnHotspotStaJoinCallBack;

    /** Station disconnected */
    // void (*OnHotspotStaLeave)(StationInfo* info);
    wifiEventHandler.OnHotspotStaLeave = OnHotspotStaLeaveCallBack;

    /** Hotspot state change */
    // void (*OnHotspotStateChanged)(int state);
    wifiEventHandler.OnHotspotStateChanged = OnHotspotStateChangedCallBack;

    // 注册 WiFi 事件
    /**
     * @brief Registers a callback for a specified Wi-Fi event.
     *
     * The registered callback will be invoked when the Wi-Fi event defined in {@link WifiEvent} occurs. \n
     *
     * @param event Indicates the event for which the callback is to be registered.
     * @return Returns {@link WIFI_SUCCESS} if the callback is registered successfully; returns an error code defined
     * in {@link WifiErrorCode} otherwise.
     * @since 1.0
     * @version 1.0
    */
    // WifiErrorCode RegisterWifiEvent(WifiEvent* event);
    errorCode = RegisterWifiEvent(&wifiEventHandler);
    if (errorCode == WIFI_SUCCESS)
    {
        printf("Register WiFi Event Successed!!!\r\n");
    }
    else
    {
        printf("Register WiFi Event Falied And ErrorCode is %d.\r\n", errorCode);
    }
}

/* 等待扫描结果的函数 */
static void waitScanResult(void)
{
    int scanTimeOut = DEF_TIMEOUT;
    while (scanTimeOut > 0)
    {
        sleep(ONE_SECOND);
        scanTimeOut--;
        if (staScanSuccess == 1)
        {
            printf("waitScanResult: WiFi Scan Result Is Success[%d]s.\r\n", (DEF_TIMEOUT - scanTimeOut));
            break;
        }
    }
    if (scanTimeOut <= 0)
    {
        printf("waitScanResult: WiFi Scan Result TimeOut.\r\n");
    }
}

/* 等待连接结果的函数 */
static int waitConnectResult(void)
{
    int connectTimeOut = DEF_TIMEOUT;
    while (connectTimeOut > 0)
    {
        sleep(ONE_SECOND);
        connectTimeOut--;
        if (staConnectSuccess == 1)
        {
            printf("waitConnectResult: WiFi Connect Result Is Success[%d]s.\r\n", (DEF_TIMEOUT - connectTimeOut));
            break;
        }
    }
    if (connectTimeOut <= 0)
    {
        printf("waitConnectResult: WiFi Connect TimeOut.\r\n");
        return 0;
    }
    return 1;
}

/* 连接 WIFI 的API接口 */
int wifiConnect(const char *ssid, const char *psk)
{
    WifiScanInfo *info = NULL;
    unsigned int size = WIFI_SCAN_HOTSPOT_LIMIT;
    static struct netif *lwipNetIf = NULL;

    // 延迟2s连接
    osDelay(200);
    printf(">>>System Init WiFi ......\r\n");

    // 初始化WIFI
    wifiInit();

    // 使能WiFi
    /**
     * @brief Enables the station mode.
     *
     * @return Returns {@link WIFI_SUCCESS} if the station mode is enabled; returns an error code defined in
     * {@link WifiErrorCode} otherwise.
     * @since 1.0
     * @version 1.0
    */
    // WifiErrorCode EnableWifi(void);
    if (EnableWifi() != WIFI_SUCCESS)
    {
        printf("Enable WiFi Falied, Error Code Is %d.\r\n", errorCode);
        return -1;
    }

    // 判断WiFi 是否激活
    /**
     * @brief Checks whether the station mode is enabled.
     *
     * @return Returns {@link WIFI_STA_ACTIVE} if the station mode is enabled; returns {@link WIFI_STA_NOT_ACTIVE}
     * otherwise.
     * @since 1.0
     * @version 1.0
    */
    // int IsWifiActive(void);
    if (IsWifiActive() != WIFI_STA_ACTIVE)
    {
        printf("WiFi Station Is No Active.\r\n");
        return -1;
    }

    // 分配内存空间,保存WiFi信息
    info = malloc(sizeof(WifiScanInfo) * WIFI_SCAN_HOTSPOT_LIMIT);
    if (info == NULL)
    {
        return -1;
    }

    // 轮询查找WiFi列表
    do
    {
        // 重置标志
        ssid_count = 0;
        staScanSuccess = 0;

        // 开始扫描
        /**
         * @brief Starts a Wi-Fi scan.
         *
         * @return Returns {@link WIFI_SUCCESS} if the Wi-Fi scan is started; returns an error code defined in
         * {@link WifiErrorCode} otherwise.
         * @since 1.0
         * @version 1.0
        */
        // WifiErrorCode Scan(void);
        Scan();

        // 等待扫描结果
        waitScanResult();

        // 获取扫描结果列表
        /**
         * @brief Obtains an array of hotspots detected in a Wi-Fi scan.
         *
         * The array of hotspots can be obtained only after the Wi-Fi scan is complete. \n
         *
         * @param result Indicates the array of hotspots detected in a Wi-Fi scan. The array is requested and released by the
         * caller. The value must be greater than or equal to {@link WIFI_SCAN_HOTSPOT_LIMIT}.
         * @param size Indicates the size of the array.
         * @return Returns {@link WIFI_SUCCESS} if the array of hotspots detected in the Wi-Fi scan is obtained; returns an
         * error code defined in {@link WifiErrorCode} otherwise.
         * @since 1.0
         * @version 1.0
        */
        // WifiErrorCode GetScanInfoList(WifiScanInfo* result, unsigned int* size);
        errorCode = GetScanInfoList(info, &size);
    } while (staScanSuccess != 1);

    // 打印WiFi信息列表
    printf("**********YuchuanHuaying WiFi Info List Start**********\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("******************YuchuanHuaying End*******************\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 selectWiFiAPConfig = {0};
            strcpy(selectWiFiAPConfig.ssid, info[i].ssid);
            strcpy(selectWiFiAPConfig.preSharedKey, psk);
            selectWiFiAPConfig.securityType = SELECT_WIFI_SECURITYTYPE;
            /**
             * @brief Adds a specified hotspot configuration for connecting to a hotspot.
             *
             * This function generates a <b>networkId</b>. \n
             *
             * @param config Indicates the hotspot configuration to add.
             * @param result Indicates the generated <b>networkId</b>. Each <b>networkId</b> matches a hotspot configuration.
             * @return Returns {@link WIFI_SUCCESS} if the specified hotspot configuration is added; returns an error code defined
             * in {@link WifiErrorCode} otherwise.
             * @since 1.0
             * @version 1.0
            */
            // WifiErrorCode AddDeviceConfig(const WifiDeviceConfig* config, int* result);
            if (AddDeviceConfig(&selectWiFiAPConfig, &result) == WIFI_SUCCESS)
            {
                /**
                 * @brief Connects to a hotspot matching a specified <b>networkId</b>.
                 *
                 * Before calling this function, call {@link AddDeviceConfig} to add a hotspot configuration. \n
                 *
                 * @param networkId Indicates the <b>networkId</b> matching the target hotspot.
                 * @return Returns {@link WIFI_SUCCESS} if the hotspot is connected; returns an error code defined in
                 * {@link WifiErrorCode} otherwise.
                 * @since 1.0
                 * @version 1.0
                */
                // WifiErrorCode ConnectTo(int networkId);
                if (ConnectTo(result) == WIFI_SUCCESS && waitConnectResult() == 1)
                {
                    printf("WiFi Connect Successed.\r\n");
                    /**
                    * @ingroup Threadsafe_Network_Interfaces
                    * @brief
                    *  This thread-safe interface is called when to find interface
                    */
                    // struct netif *netifapi_netif_find(const char *name);
                    lwipNetIf = 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 (lwipNetIf)
    {
        dhcp_start(lwipNetIf);
        printf("Begain To DHCP.\r\n");
    }

    // 等待DHCP
    for (;;)
    {
        if (dhcp_is_bound(lwipNetIf) == ERR_OK)
        {
            printf("<--YuchuanHuaying DHCP state:OK -->\r\n");

            // 打印获取到的IP信息
            /**
             * @ingroup Threadsafe_Network_Interfaces
             * @brief
             *  This API is used to call all netif related APIs in a thread safe manner. The netif related APIs must be
             *  of prototype to receive only struct netif* as argument and return type can of type err_t or void. You
             *  must pass either viodfunc or errtfunc.
             *
             * @param[in]    netif          Indicates the network interface to be passed as argument.
             * @param[in]    voidfunc       Callback with return type of void, will be called if errtfunc is NULL.
             * @param[in]    errtfunc       Callback with return type of err_t.
             *
             * @returns
             *  0 : On success. \n
             *  Negative value : On failure.
             *
             * @note
             * The prototype for netifapi_void_fn and netifapi_errt_fn are as follows:\n
             * typedef void (*netifapi_void_fn)(struct netif *netif); \n
             * typedef err_t (*netifapi_errt_fn)(struct netif *netif); \n
            */
            // err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc,netifapi_errt_fn errtfunc);
            netifapi_netif_common(lwipNetIf, dhcp_clients_info_show, NULL);
            break;
        }
        printf("<--YuchuanHuaying DHCP state:Inprogress -->\r\n");
        osDelay(100);
    }

    osDelay(100);

    return 0;
}

include/wifi_connect.h

/*
 * Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __WIFI_CONNECT_H__
#define __WIFI_CONNECT_H__

int wifiConnect(const char *ssid, const char *psk);

#endif /* __WIFI_CONNECT_H__ */

编译调试

//applications/sample/BearPi/BearPi-HM_Nano/sample/D3_YuchuanUDPServer/BUILD.gn

static_library("yuchuanUDPServer"){
    sources = [
        "yuchuanUDPServer.c",
        "src/wifi_connect.c",
    ]

    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/kal/cmsis",
        "//foundation/communication/wifi_lite/interfaces/wifiservice",
        "//device/bearpi/bearpi_hm_nano/sdk_liteos/third_party/lwip_sack/include/lwip",
        "include",
    ]
}

修改 BUILD.gn 文件

修改 applications\BearPi\BearPi-HM_Nano\sample 路径下 BUILD.gn 文件,指定 yuchuanUDPServer参与编译。

# Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

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

lite_component("sample") {
    features = [
        #"A1_kernal_thread:thread_example",
        #"A2_kernel_timer:timer_example",
        #"A3_kernel_event:event_example",
        #"A4_kernel_mutex:mutex_example",
        #"A5_kernel_semaphore:semaphore_example",
        #"A6_kernel_message:message_example",

        #"B1_basic_led_blink:led_example",
        #"B2_basic_button:button_example",
        #"B3_basic_pwm_led:pwm_example",
        #"B4_basic_adc:adc_example", 
        #"B5_basic_i2c_nfc:i2c_example",
        #"B6_basic_uart:uart_example",
        
        #"C1_e53_sf1_mq2:e53_sf1_example",
        #"C2_e53_ia1_temp_humi_pls:e53_ia1_example",
        #"C3_e53_sc1_pls:e53_sc1_example",
        #"C4_e53_sc2_axis:e53_sc2_example",
        #"C5_e53_is1_infrared:e53_is1_example",

        #"D1_iot_wifi_ap:wifi_ap",
        #"D2_iot_wifi_sta_connect:wifi_sta_connect",        
        #"D3_iot_udp_client:udp_client",
        #"D4_iot_tcp_server:tcp_server",
        #"D5_iot_mqtt:iot_mqtt",        
        #"D6_iot_cloud_oc:oc_mqtt",
        #"D7_iot_cloud_onenet:onenet_mqtt",
        #"D8_iot_cloud_oc_smoke:cloud_oc_smoke",
        #"D9_iot_cloud_oc_light:cloud_oc_light",
        #"D10_iot_cloud_oc_manhole_cover:cloud_oc_manhole_cover",
        #"D11_iot_cloud_oc_infrared:cloud_oc_infrared",
        #"D12_iot_cloud_oc_agriculture:cloud_oc_agriculture",
        #"D13_iot_cloud_oc_gps:cloud_oc_gps",
        #"D3_YuchuanIoTUDPClient:yuchuanUDPClient",
        #"D3_YuchuanUDP:yuchuanUDP",
        #"D4_YuchuanTCPServer:yuchuanTCPServer",
        "D3_YuchuanUDPServer:yuchuanUDPServer",
    ]
}

运行结果

示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,会打印模块的本地IP,如本例程中的 192.168.43.130 ,并开始准备获取客户端的请求链接

ready to OS start
sdk ver:Hi3861V100R001C00SPC025 2020-09-03 18:10:00
formatting spiffs...
FileSystem mount ok.
wifi init success!

hiview init success.00 00:00:00 0 132 D 0/HIVIEW: log limit init success.
00 00:00:00 0 132 I 1/SAMGR: Bootstrap core services(count:3).
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b1268 TaskPool:0xe523c
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b1274 TaskPool:0xe525c
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b1740 TaskPool:0xe527c
00 00:00:00 0 164 I 1/SAMGR: Init service 0x4b1274 <time: 0ms> success!
00 00:00:00 0 64 I 1/SAMGR: Init service 0x4b1268 <time: 0ms> success!
00 00:00:00 0 8 I 1/SAMGR: Init service 0x4b1740 <time: 0ms> success!
00 00:00:00 0 8 I 1/SAMGR: Initialized all core system services!
00 00:00:00 0 64 I 1/SAMGR: Bootstrap system and application services(count:0).
00 00:00:00 0 64 I 1/SAMGR: Initialized all system and application services!
00 00:00:00 0 64 I 1/SAMGR: Bootstrap dynamic registered services(count:0).
>>>System Init WiFi ......
>>>WiFi Init Start ......
Register WiFi Event Successed!!!
WiFi CallBack Function Is Success Scan:0 ,0.
+NOTICE:SCANFINISH
WiFi CallBack Function Is Success Scan:1 ,12.
waitScanResult: WiFi Scan Result Is Success[1]s.
**********YuchuanHuaying WiFi Info List Start**********
no:001, ssid:886699                        , rssi:  -38
no:002, ssid:Warehouse                     , rssi:  -60
no:003, ssid:Warehouse                     , rssi:  -66
no:004, ssid:Packing                       , rssi:  -73
no:005, ssid:Mobile-WiFi                   , rssi:  -74
no:006, ssid:306C2                         , rssi:  -78
no:007, ssid:Warehouse                     , rssi:  -78
no:008, ssid:Warehouse                     , rssi:  -79
no:009, ssid:Warehouse                     , rssi:  -84
no:010, ssid:WIFI_Network                  , rssi:  -84
no:011, ssid:WIFI_Network                  , rssi:  -89
no:012, ssid:LightTouch                    , rssi:  -76
******************YuchuanHuaying End*******************
Select:  1 wireless, Waiting...
+NOTICE:CONNECTED
waitConnectResult: WiFi Connect Result Is Success[1]s.
WiFi Connect Successed.
Begain To DHCP.
<--YuchuanHuaying DHCP state:Inprogress -->
<--YuchuanHuaying DHCP state:OK -->
server :
	server_id : 192.168.137.1
	mask : 255.255.255.0, 1
	gw : 192.168.137.1
	T0 : 604800
	T1 : 302400
	T2 : 453600
clients <1> :
	mac_idx mac             addr            state   lease   tries   rto     
	0       e41131a6b96a    192.168.137.15  10      0       1       4       
Recv : YuchuanHuaying..
Recv : Hello Meimei.
Recv : Aiyijia.

使用 Socket tool 创建客户端用于测试。

创建TCP_Clien

在创建客户端后点击“连接”,在数据发送窗口输入要发送的数据,点击发送后服务端会回复固定消息,且开发板收到消息后会通过日志打印出来。

Recv : YuchuanHuaying..
Recv : Hello Meimei.
Recv : Aiyijia.

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。