HarmonyOS小熊派 | HarmonyOS WiFi编程开发--TCP客户端

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

BearPi-HM_Nano开发板WiFi编程开发——TCP客户端

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

BearPi-HM_Nano

TCP协议相关API介绍

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

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

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
NAME
       connect - initiate a connection on a socket

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

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

DESCRIPTION
       The  connect()  system call connects the socket referred to by the file descriptor sockfd to the address specified by addr.
       The addrlen argument specifies the size of addr.  The format of the address in addr is determined by the address  space  of
       the socket sockfd; see socket(2) for further details.

       If  the  socket sockfd is of type SOCK_DGRAM, then addr is the address to which datagrams are sent by default, and the only
       address from which datagrams are received.  If the socket is of type SOCK_STREAM or SOCK_SEQPACKET, this call  attempts  to
       make a connection to the socket that is bound to the address specified by addr.

       Generally,  connection-based protocol sockets may successfully connect() only once; connectionless protocol sockets may use
       connect() multiple times to change their association.  Connectionless sockets may dissolve the association by connecting to
       an address with the sa_family member of sockaddr set to AF_UNSPEC (supported on Linux since kernel 2.2).

RETURN VALUE
       If the connection or binding succeeds, zero is returned.  On error, -1 is returned, and errno is set appropriately.

描述:

sockfd是由socket函数返回的套接字描述符,第二个、第三个参数分别是一个指向套接字地址结构的指针和结构的大小。

3、send()

ssize_t send(int sockfd, const void *buf, size_t 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);

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 difference 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.

描述:

功能:不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

参数一:指定发送端套接字描述符;

参数二:存放应用程序要发送数据的缓冲区;

参数三:实际要发送的数据的字节数;

参数四:一般置为0。同步Socket的send函数的执行流程,当调用该函数时,send先比较待发送数据的长度len和套接字s的发送缓冲的长度(因为待发送数据是要copy到套接字s的发送缓冲区的,注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里):
1.如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;

2.如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么 send就比较s的发送缓冲区的剩余空间和len:

      (i)如果len大于剩余空间大小send就一直等待协议把s的发送缓冲中的数据发送完;

      (ii)如果len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里。

3.如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。

注意:send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回 SOCKET_ERROR)

3、recv()

ssize_t recv(int sockfd, void *buf, size_t 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);

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  features  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 nonblock‐
       ing (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.

描述:

功能:不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。

参数一:指定接收端套接字描述符;

参数二:指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;

参数三:指明buf的长度;

参数四 :一般置为0。


同步Socket的recv函数的执行流程:当应用程序调用recv函数时,recv先等待s的发送缓冲中的数据被协议传送完毕,

如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR;

如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直
等待,直到协议把数据接收完毕;

当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),recv函数返回其实际copy的字节数;

如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。

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 fc‐
       ntl(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 obtain 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 unlink(2), the file is deleted.

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

ERRORS
       EBADF  fd isn't a valid open file descriptor.

       EINTR  The close() call was interrupted by a signal; see signal(7).

       EIO    An I/O error occurred.

       ENOSPC, EDQUOT
              On  NFS,  these  errors are not normally reported against the first write which exceeds the available storage space,
              but instead against a subsequent write(2), fsync(2), or close().

       See NOTES for a discussion of why close() should not be retried after an error.

描述:

关闭socket文件描述符

描述:

关闭socket文件描述符

软件设计

主要代码分析

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

TCP客户端创建流程介绍 

1630765684(1).png

实现TCP客户端

项目结构目录:

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

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

yuchuan_tcp_client.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_connect.h"

#include "lwip/sockets.h"

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

static const char *send_data = "YuchuanHuaying TCP Client Send Data.";

int sock_fd;

/* 创建TCP客户端的任务函数 */
static void yuchuanTCPClientTask(void)
{
    // 服务器地址信息
    struct sockaddr_in send_addr;
    socklen_t addr_length = sizeof(send_addr);
    char recvBuff[512];

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

    // 创建socket
    if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("Create Socktet Falied.\r\n");
        exit(1);
    }
    
    // 初始化预连接的服务器地址
    send_addr.sin_family = AF_INET;
    send_addr.sin_port = htons(_PROT_);
    send_addr.sin_addr.s_addr = inet_addr("10.81.234.13");
    addr_length = sizeof(send_addr);

    connect(sock_fd, (struct sockaddr *)&send_addr, addr_length);

    ssize_t ret;
    while (1)
    {
        bzero(recvBuff, sizeof(recvBuff));

        // 发送数据到服务器
        send(sock_fd, send_data,strlen(send_data), 0);

        // 休眠一段时间
        // sleep(10);

        // send(sock_fd)
        /* if ((ret = send(sock_fd, send_data,strlen(send_data), 0)) == -1)
        {
            perror("Send : ");
        } */

        /* if ((ret = recv(sock_fd, recvBuff,sizeof(recvBuff), 0)) == -1)
        {
            printf("Recv Error.\r\n");
        } */

        // 接收服务器返回的字符串
        recv(sock_fd, recvBuff,sizeof(recvBuff), 0);

        printf("Recv : %s\r\n", recvBuff);
    }
    
    // 关闭这个 socket
    close(sock_fd);
}

/* TCP 客户端的函数入口 */
static void yuchuanTCPClientEntry(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 = "YuchuanTCPClientTask";
    if (osThreadNew((osThreadFunc_t)yuchuanTCPClientTask, NULL, &threadAttr) == NULL)
    {
        printf("Falied To Create YuchuanTCPClientTask.\r\n");
    }
}

APP_FEATURE_INIT(yuchuanTCPClientEntry);

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

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

    include_dirs = [
        "//utils/native/lite/include",
        "//kernel/liteos_m/kal/cmsis",
        "//foundation/communication/wifi_lite/interfaces/wifiservice",
        "include",
    ]
}

修改 BUILD.gn 文件

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

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

运行结果

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

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:0x4b1228 TaskPool:0xe503c
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b1234 TaskPool:0xe505c
00 00:00:00 0 132 I 1/SAMGR: Init service:0x4b1700 TaskPool:0xe507c
00 00:00:00 0 164 I 1/SAMGR: Init service 0x4b1234 <time: 0ms> success!
00 00:00:00 0 64 I 1/SAMGR: Init service 0x4b1228 <time: 0ms> success!
00 00:00:00 0 8 I 1/SAMGR: Init service 0x4b1700 <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 ,25.
waitScanResult: WiFi Scan Result Is Success[1]s.
**********YuchuanHuaying WiFi Info List Start**********
no:001, ssid:886699                        , rssi:  -56
no:002, ssid:Warehouse                     , rssi:  -64
no:003, ssid:Warehouse                     , rssi:  -69
no:004, ssid:Packing                       , rssi:  -74
no:005, ssid:Voyager                       , rssi:  -75
no:006, ssid:We.Connect                    , rssi:  -76
no:007, ssid:Warehouse                     , rssi:  -79
no:008, ssid:Warehouse                     , rssi:  -79
no:009, ssid:We.Connect                    , rssi:  -79
no:010, ssid:Warehouse                     , rssi:  -79
no:011, ssid:Warehouse                     , rssi:  -81
no:012, ssid:Warehouse                     , rssi:  -83
no:013, ssid:Warehouse                     , rssi:  -84
no:014, ssid:WIFI_Network                  , rssi:  -85
no:015, ssid:We.Connect                    , rssi:  -87
no:016, ssid:Mobile-WiFi                   , rssi:  -87
no:017, ssid:Warehouse                     , rssi:  -88
no:018, ssid:Warehouse                     , rssi:  -88
no:019, ssid:Voyager                       , rssi:  -88
no:020, ssid:WIFI_Network                  , rssi:  -89
no:021, ssid:Warehouse                     , rssi:  -91
no:022, ssid:WIFI_Network                  , rssi:  -92
no:023, ssid:Warehouse                     , rssi:  -93
no:024, ssid:LightTouch                    , rssi:  -74
no:025, ssid:Openspace                     , 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       a0113148d324    192.168.137.104 10      0       1       4       
Recv : YuchuanHuaying Hello.
Recv : hello.
Recv : yuchuan.

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

创建TCP_Clien

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

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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

举报
请填写举报理由
0/200