HarmonyOS小熊派 | HarmonyOS WiFi编程开发--TCP服务器

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

BearPi-HM_Nano开发板WiFi编程开发——TCP服务器

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

BearPi-HM_Nano

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、listen()

int listen(int s, int backlog)
NAME
       listen - listen for connections on a socket

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

       int listen(int sockfd, int backlog);

DESCRIPTION
       listen()  marks  the  socket  referred  to  by sockfd as a passive socket, that is, as a socket that will be used to accept incoming connection requests using ac‐
       cept(2).

       The sockfd argument is a file descriptor that refers to a socket of type SOCK_STREAM or SOCK_SEQPACKET.

       The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow.  If a connection request arrives when the queue  is
       full,  the  client  may  receive an error with an indication of ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be ignored so
       that a later reattempt at connection succeeds.

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

描述:

当socket创建后,它通常被默认为是主动套接口,也就是说是默认为要马上调用connect函数的,而作为服务器是需要被动接受的,所以需要调用linsten函数将主动套接口转换成被动套接口。调用linsten函数后,内核将从该套接口接收连接请求。

4、accept()

int accept(s, addr, addrlen)   
NAME
       accept, accept4 - accept a connection on a socket

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

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

       #define _GNU_SOURCE             /* See feature_test_macros(7) */
       #include <sys/socket.h>

       int accept4(int sockfd, struct sockaddr *addr,
                   socklen_t *addrlen, int flags);

描述:

此函数返回已经握手完成的连接的套接口。注意:此处的套接口不同于服务器开始创建的监听套接口,此套接口是已经完成连接的套接口,监听套接口只是用来监听。

5、recv()

int recv( SOCKET s, char *buf, int  len, int flags)   
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);

描述:

recv函数用来从TCP连接的另一端接收数据

6、send()

int send( SOCKET s,char *buf,int len,int flags )
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);

描述: send函数用来向TCP连接的另一端发送数据。

软件设计

主要代码分析

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

  1. 通过 socket 接口创建一个socket,AF_INT表示ipv4,SOCK_STREAM表示使用tcp协议
  2. 调用 bind 接口绑定socket和地址。
  3. 调用 listen 接口监听(指定port监听),通知操作系统区接受来自客户端链接请求,第二个参数:指定队列长度
  4. 调用accept接口从队列中获得一个客户端的请求链接
  5. 调用 recv 接口接收客户端发来的数据
  6. 调用 send 接口向客户端回复固定的数据

项目结构目录:

yuchuanhuaying@yuchuanhuaying:~/MasterData/PublicSharedData/MasterHarmonyOSCode/SmartIoTPro/applications/sample/BearPi/BearPi-HM_Nano/sample/D4_YuchuanTCPServer$ tree
.
├── BUILD.gn
├── include
│   └── wifi_connect.h
├── src
│   └── wifi_connect.c
└── yuchuan_tcp_server.c

2 directories, 4 files

yuchuan_tcp_server.c

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

#define WIFI_ACCOUNT "uchuanuaying"
#define WIFI_PASSWD "sdsdasrr"
#define _PROT_ 8888
#define TCP_BACKLOG 10

int sock_fd, new_fd;
char recvBuff[512];
char *buf = "YuchuanHuaying I'm TCP Server Message!!!";

/* 创建Yuchuan TCP Server 任务 */
static void yuchuanTCPServerTask(void)
{
    // 服务器地址信息
    struct sockaddr_in server_sock;

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

    int sin_size;

    struct sockaddr_in *client_add;

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

    // 创建socket
    if ((sock_fd = socket(AF_INET, SOCK_STREAM, 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);
    }

    // 调用 listen 函数监听指定端口
    if (listen(sock_fd, TCP_BACKLOG) == -1)
    {
        perror("Listen Is Error.\r\n");
        exit(1);
    }

    printf("Start Accept.\r\n");

    // 调用 accept 函数从队列中获取数据
    while (1)
    {
        sin_size = sizeof(struct sockaddr_in);

        if ((new_fd = accept(sock_fd, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
        {
            perror("Accept Is Error.\r\n");
            continue;
        }

        client_add = malloc(sizeof(struct sockaddr));

        printf("accept addr.\r\n");

        if (client_add != NULL)
        {
            memcpy(client_add, &client_sock, sizeof(struct sockaddr));
        }

        // 处理目标
        ssize_t ret;
        while (1)
        {
            if ((ret = recv(new_fd, recvBuff, sizeof(recvBuff), 0)) == -1)
            {
                printf("Recv Is Error.\r\n");
            }
            printf("Recv : %s.\r\n", recvBuff);
            sleep(2);

            if ((ret = send(new_fd, buf, strlen(buf) + 1, 0)) == -1)
            {
                perror("Send : Message Falied.\r\n");
            }
            sleep(2);
        }
        close(new_fd);
    }
}

/* TCP Server 端 */
static void yuchuanTCPServerEntity(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 = 25;
    threadAttr.name = "YuchuanTCPServerTask";

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

APP_FEATURE_INIT(yuchuanTCPServerEntity);

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/D4_YuchuanTCPServer/BUILD.gn

static_library("yuchuanTCPServer"){
    sources = [
        "yuchuan_tcp_server.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 文件,指定 yuchuanTCPServer 参与编译。

# 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",
    ]
}

运行结果

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

ready to OS start
sdk ver:Hi3861V100R001C00SPC025 2020-09-03 18:10:00
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:0x4b12c8 TaskPool:0xe523c
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b12d4 TaskPool:0xe525c
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b17a0 TaskPool:0xe527c
00 00:00:00 0 164 I 1/SAMGR: Init service 0x4b12d4 <time: 0ms> success!
00 00:00:00 0 64 I 1/SAMGR: Init service 0x4b12c8 <time: 0ms> success!
00 00:00:00 0 8 I 1/SAMGR: Init service 0x4b17a0 <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:YuchuanHuaying                , rssi:  -35
no:002, ssid:TP-LINK_5E52                  , rssi:  -62
no:003, ssid:@PHICOMM_4A                   , rssi:  -65
no:004, ssid:HUAWEI-N67AFG                 , rssi:  -69
no:005, ssid:KWONG_2.4G.ASUS               , rssi:  -77
no:006, ssid:Redmi_7176                    , rssi:  -77
no:007, ssid:                              , rssi:  -78
no:008, ssid:360WiFi-705                   , rssi:  -82
no:009, ssid:声学实验室2.4G           , rssi:  -83
no:010, ssid:Liao                          , rssi:  -84
no:011, ssid:lele                          , rssi:  -88
no:012, ssid:TOPFU                         , rssi:  -88
******************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:Inprogress -->
<--YuchuanHuaying DHCP state:Inprogress -->
<--YuchuanHuaying DHCP state:Inprogress -->
<--YuchuanHuaying DHCP state:OK -->
server :
        server_id : 192.168.43.1
        mask : 255.255.255.0, 1
        gw : 192.168.43.1
        T0 : 3600
        T1 : 1800
        T2 : 3150
clients <1> :
        mac_idx mac             addr            state   lease   tries   rto
        0       08113180a448    192.168.43.130  10      0       1       3
Start Accept.
accept addr.
Recv : YuchuanHuaying Hello.
Recv : Helloo Yelying Hello.
Recv : MoniKa Yelying Hello.

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

创建TCP_Clien

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

Start Accept.
accept addr.
Recv : YuchuanHuaying Hello.
Recv : Helloo Yelying Hello.
Recv : MoniKa Yelying Hello.

tcp.PNG

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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