【普中Hi3861开发攻略--基于鸿蒙OS】-- 第 29 章 WIFI 实验-TCP 通信

(1)实验平台:

普中Hi3861鸿蒙物联网WIFI套件https://item.taobao.com/item.htm?id=829136021914(2)资料下载:普中科技-各型号产品资料下载链接


如今物联网市场异常火爆, WIFI 是物联网中非常重要的角色, 现在基本上家家户户都有 WIFI 网络, 通过 WIFI 接入到互联网, 成了智能家居产品普遍的选择。 Hi3861 内部已集成 WIFI 功能, 可以说它就是为 WIFI 无线连接而生的。 本章来学习 WIFI 的 TCP 网络通信, 使用 Hi3861 开发 WIFI 是非常简单而美妙的,让大家在学习物联网中变的简单有趣。 本章分为如下几部分内容:

[29.1 实验介绍](#29.1 实验介绍)

[29.1.1 实验简介](#29.1.1 实验简介)

[29.1.1.1 TCP 协议概述](#29.1.1.1 TCP 协议概述)

[29.1.1.2 TCP 通信实现](#29.1.1.2 TCP 通信实现)

[29.1.2 实验目的](#29.1.2 实验目的)

[29.1.3 WIFI 函数使用](#29.1.3 WIFI 函数使用)

[29.1.3.1 connect 函数](#29.1.3.1 connect 函数)

[29.1.3.2 send 函数](#29.1.3.2 send 函数)

[29.1.3.3 recv 函数](#29.1.3.3 recv 函数)

[29.2 硬件设计](#29.2 硬件设计)

[29.3 软件设计](#29.3 软件设计)

[29.4 实验现象](#29.4 实验现象)


29.1 实验介绍

29.1.1 实验简介

TCP 通信是基于 TCP/IP 协议栈实现的, 主要用于在设备与其他网络设备之间建立可靠的、 面向连接的通信。

29.1.1.1 TCP 协议概述

定义: TCP(Transmission Control Protocol, 传输控制协议) 是一种面向连接的、 可靠的、 基于字节流的传输层通信协议。

特点:

●面向连接: 通信双方必须先建立连接才能进行数据的传输, 类似于打电话需要先拨号建立连接。

●可靠性: TCP 通过校验和、 重传控制、 序号标识、 滑动窗口、 确认应答等机制实现可靠传输, 确保数据无差错、 不丢失、 不重复, 且按序到达。

●字节流服务: TCP 把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。

●全双工通信: TCP 允许通信双方的应用程序在任何时候都能发送数据, TCP连接的两端都设有发送缓存和接收缓存, 用来临时存放双方通信的数据。

29.1.1.2 TCP 通信实现

在 Hi3861 上实现 TCP 通信, 通常需要以下几个步骤:

1、 TCP 服务端实现步骤

●创建 socket: 使用 socket()函数创建一个 socket, 指定使用 IPv4 地址(AF_INET) 和 TCP 协议(SOCK_STREAM) 。

●绑定地址: 使用 bind()函数将 socket 与特定的 IP 地址和端口号绑定起来。

●监听连接: 通过 listen()函数使 socket 进入被动监听状态, 等待客户端的连接请求。

●接受连接: 使用 accept()函数接受客户端的连接请求, 建立连接。

●接收和发送数据: 通过 recv()和 send()函数接收和发送数据。

●关闭连接: 数据传输完成后, 使用 close()函数关闭 socket 连接。

2、 TCP 客户端实现步骤

●创建 socket: 同样使用 socket()函数创建一个 socket。

●配置服务端地址: 创建 sockaddr_in 结构体, 配置服务端的 IP 地址和端口号。

●连接服务端: 使用 connect()函数向服务端发起连接请求。

●发送和接收数据: 连接建立后, 通过 send()和 recv()函数发送和接收数据。

●关闭连接: 数据传输完成后, 使用 close()函数关闭 socket 连接。

29.1.2 实验目的

连接路由器热点, 打开网络调试助手, 选择 TCP 协议连接, 即可与开发板进行 TCP 通信, 开发板作为客户端, 电脑作为服务端。

29.1.3 WIFI 函数使用

29.1.3.1 connect 函数

用于客户端主动连接服务器, 建立 TCP 连接。 函数原型:

cpp 复制代码
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数:

sockfd: 由 socket 函数返回的套接字描述符。 这个描述符标识了一个网络端点, 客户端将使用这个端点来与服务器进行通信。

addr: 指向 sockaddr 结构的指针, 该结构包含了服务器的地址信息, 包括IP 地址和端口号。 在实际使用中, 通常会使用 sockaddr_in( 对于 IPv4) 或sockaddr_in6(对于 IPv6) 结构来填充这个参数。

addrlen: addr 参数所指向的地址结构的长度。 这个长度确保了 connect 函数能够正确地解析地址信息。

返回值:

0: 连接成功。

-1: 连接失败。 此时, 全局变量 errno 会被设置为一个错误码, 以指示连接失败的具体原因。 常见的错误码包括 ECONNREFUSED(连接被拒绝) 、 ETIMEDOUT (连接超时) 等。

29.1.3.2 send 函数

用于 TCP 在已连接的套接字(socket) 上发送数据。 这是 TCP/IP 协议栈中非常核心的一个函数, 用于实现数据的可靠传输。 函数原型:

cpp 复制代码
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

参数:

sockfd: 已连接套接字的文件描述符或句柄。

buf: 指向包含要发送数据的缓冲区的指针。

len: 要发送的字节数。

flags: 控制函数行为的标志位, 通常设置为 0。

返回值:

成功时, 返回实际发送的字节数。

失败时, 返回-1, 并设置全局变量 errno 以指示错误原因;

29.1.3.3 recv 函数

用于从 TCP 连接的另一端接收数据。 函数原型:

cpp 复制代码
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

参数:

sockfd: 指定接收数据的套接字描述符(socket descriptor) , 它唯一标识了一个套接字。

buf: 指向一个缓冲区的指针, 该缓冲区用于存放 recv 函数接收到的数据。

len: 指定缓冲区 buf 的长度, 即最多可以接收多少字节的数据。

flags: 调用操作标志位, 用于控制 recv 函数的行为。 在大多数情况下, 这个参数被设置为 0。

返回值: 返回接收到字节数, 如果出现错误返回-1;

当应用程序调用 recv 函数时, 它执行以下操作:

等待数据: 如果套接字的发送缓冲区中没有数据或者数据正在被协议层传送, recv 函数会等待, 直到有数据到达并被协议层接收完毕。

复制数据: 当数据到达并被接收完毕后, recv 函数会从套接字的接收缓冲区中复制数据到用户指定的缓冲区(buf) 中。 注意, 如果接收到的数据量大于缓冲区的长度, 可能需要多次调用 recv 函数来接收所有数据。

返回接收到的字节数: recv 函数返回实际复制到缓冲区中的字节数。 如果接收过程中出现错误, 则返回-1(或 SOCKET_ERROR) , 并设置相应的错误码(通过 errno 或 WSAGetLastError 获取) 。 如果连接被对方正常关闭, 则返回 0。

29.2 硬件设计

由于 Hi3861 内置 WIFI 功能, 所以直接在开发板上使用即可, 无需额外连接。

29.3 软件设计

将前面章节创建好的工程模板, 复制一份, 重命名为 25_wifi_tcp, 如下所示:

(1) 修改 demo 文件夹下的 BUILD.gn 文件, 如下所示:

(2) 添加工程编译文件路径, 如下所示

(3) 修改 template.c 文件, 代码如下:

cpp 复制代码
/**
 ****************************************************************************************************
 * @file        template.c
 * @author      普中科技
 * @version     V1.0
 * @date        2024-06-05
 * @brief       WIFI TCP实验
 * @license     Copyright (c) 2024-2034, 深圳市普中科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:普中-Hi3861
 * 在线视频:https://space.bilibili.com/2146492485
 * 公司网址:www.prechin.cn
 * 购买地址:
 *
 ****************************************************************************************************
 * 实验现象:开发板连接路由器热点,打开网络调试助手,选择TCP协议连接,即可与开发板进行TCP通信
 *
 ****************************************************************************************************
 */

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

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "bsp_led.h"
#include "bsp_wifi.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"
#include "lwip/api_shell.h"


//LED任务
osThreadId_t LED_Task_ID; //led任务ID

void LED_Task(void)
{
    led_init();//LED初始化

    while (1) 
    {
        LED(1); 
        usleep(200*1000); //200ms
        LED(0);
        usleep(200*1000); //200ms
    }
}
//LED任务创建
void led_task_create(void)
{
    osThreadAttr_t taskOptions;
    taskOptions.name = "LEDTask";            // 任务的名字
    taskOptions.attr_bits = 0;               // 属性位
    taskOptions.cb_mem = NULL;               // 堆空间地址
    taskOptions.cb_size = 0;                 // 堆空间大小
    taskOptions.stack_mem = NULL;            // 栈空间地址
    taskOptions.stack_size = 1024;           // 栈空间大小 单位:字节
    taskOptions.priority = osPriorityNormal; // 任务的优先级

    LED_Task_ID = osThreadNew((osThreadFunc_t)LED_Task, NULL, &taskOptions); // 创建任务1
    if (LED_Task_ID != NULL)
    {
        printf("ID = %d, Create LED_Task_ID is OK!\n", LED_Task_ID);
    }
}

//控制任务
osThreadId_t WIFI_Task_ID; //任务ID

#define WIFI_SSID "普中科技"
#define WIFI_PAWD "88888888.@"

#define TCP_SERVER_IP "192.168.101.16"
#define TCP_SERVER_PORT 8000

void WIFI_Task(void)
{
    int socket_fd = 0;
    char buff[256];
    int re = 0;

    // 连接Wifi
    WiFi_connectHotspots(WIFI_SSID, WIFI_PAWD);
    socket_fd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字(TCP)
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(TCP_SERVER_PORT);
    addr.sin_addr.s_addr = inet_addr(TCP_SERVER_IP); // 填写服务器的IP地址

    re = connect(socket_fd, (struct sockaddr *)&addr, sizeof(addr)); // 连接服务器
    if (re == -1) 
    {
        printf("Failed to connect to the server\r\n");
        return;
    }
    printf("Connection to server successful\r\n");

    // 发送第一条数据
    send(socket_fd, "Connection to server successful.", strlen("Connection to server successful."), 0);

    while (1) 
    {
        memset_s(buff, sizeof(buff), 0, sizeof(buff));
        re = recv(socket_fd, buff, sizeof(buff), 0); //	接收客户端发送过来的消息
        if (re <= 0) 
        {
            break;
        } 
        else 
        {
            printf("Receive data received by the server: %s\r\n", buff);
            send(socket_fd, buff, sizeof(buff), 0);
        }
    }

    close(socket_fd);
}
//任务创建
void wifi_task_create(void)
{
    osThreadAttr_t taskOptions;
    taskOptions.name = "wifiTask";       // 任务的名字
    taskOptions.attr_bits = 0;               // 属性位
    taskOptions.cb_mem = NULL;               // 堆空间地址
    taskOptions.cb_size = 0;                 // 堆空间大小
    taskOptions.stack_mem = NULL;            // 栈空间地址
    taskOptions.stack_size = 1024*10;           // 栈空间大小 单位:字节
    taskOptions.priority = osPriorityNormal; // 任务的优先级

    WIFI_Task_ID = osThreadNew((osThreadFunc_t)WIFI_Task, NULL, &taskOptions); // 创建任务
    if (WIFI_Task_ID != NULL)
    {
        printf("ID = %d, WIFI_Task_ID Create OK!\n", WIFI_Task_ID);
    }
}

/**
 * @description: 初始化并创建任务
 * @param {*}
 * @return {*}
 */
static void template_demo(void)
{
    printf("普中-Hi3861开发板--WIFI TCP实验\r\n");
    led_task_create();
    wifi_task_create();//任务创建
}
SYS_RUN(template_demo);

29.4 实验现象

将程序下载到开发板内(可参考"2.2.5 程序下载运行"章节) , 打开串口调试助手"\5--开发工具\4-串口调试助手\UartAssist.exe" , 波特率设置为115200, 实验现象: 连接路由器热点, 打开网络调试助手, 选择 TCP 协议连接,即可与开发板进行 TCP 通信, 开发板作为客户端, 电脑作为服务端。

相关推荐
hazy1k5 小时前
51单片机基础-ADC模数转换
stm32·单片机·嵌入式硬件·51单片机·1024程序员节
顾晨阳——6 小时前
GPIO总结
单片机·嵌入式硬件·gpio
嵌入式老牛6 小时前
【无标题】
单片机·嵌入式硬件·rtc
IT阳晨。6 小时前
【STM32】看门狗
stm32·嵌入式硬件
mftang6 小时前
IO 开漏模式的特征和STM32 IO开路模式的配置和应用
stm32·嵌入式硬件·开漏模式
普中科技7 小时前
【普中DSP28335开发攻略】-- 第 9 章 蜂鸣器实验
单片机·嵌入式硬件·蜂鸣器·dsp28335·ccs·普中科技
ShiMetaPi8 小时前
操作【GM3568JHF】FPGA+ARM异构开发板 使用指南:串口
arm开发·单片机·嵌入式硬件·fpga开发·rk3568
点灯小铭8 小时前
基于单片机的两路PWM信号输出及频率占空比相位差调节系统
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
普中科技8 小时前
【普中STM32F1xx开发攻略--标准库版】-- 第 9 章 STM32 固件库介绍
stm32·单片机·嵌入式硬件·arm·普中科技·固件库