ESP32C3学习&开发之路-TCP客户端实现

16 篇文章 2 订阅
13 篇文章 5 订阅


前言

本次实现使用ESP32C3创建AP和TCP客户端,电脑连接ESP32C3的AP并使用网络调试助手创建一个TCP服务器,ESP32C3客户端自动连接电脑的服务器并发送数据到电脑服务器。


一、TCP协议

1.什么是TCP协议

TCP(Transmission Control Protocol,传输控制协议),TCP 是重要的传输层协议,它和 UDP 不同,传输层软件 TCP 的目的是允许数据同网络上的另外站点进行可靠的交换。它能提供端口编号的译码,以识别主机的应用程序,而且完成数据的可靠传输。
TCP与IP用来指示一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇,TCP/IP是一个网络协议族的名字。

2.TCP客户端工作流程

一个正常的TCP客户端建立连接都有这三个步骤:
1)TCP客户端与服务器的三次握手;
2)数据发送和接收;
3)四次挥手关闭连接。
相关socket流程图如下:
在这里插入图片描述
TCP/IP的socket相关知识各位朋友请自己查阅,这部分细节还是很多的,这里只做简单介绍一下,主要还是ESP32C3的应用。

二、ESP32C3创建TCP客户端

ESP32C3集成了TCP/IP协议栈,并通过lwip库来实现相关网络功能,下面介绍如何简单实现一个TCP客户端的工程。

1.引入头文件

在这里插入图片描述

2.定义相关变量

在这里插入图片描述
定义WiFi的名称、密码、使用的通道和可接入AP的设备数;还有服务器地址和端口等;
部分参数需要打开menuconfig来配置:
在这里插入图片描述

3.TCP客户端任务函数实现

在这里插入图片描述

4.WiFi模式的初始化

设置WiFi为AP模式:
在这里插入图片描述
WiFi事件回调函数:
在这里插入图片描述

5.main函数

在这里插入图片描述

6.工程源码

#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "addr_from_stdin.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/sockets.h"


#define EXAMPLE_ESP_WIFI_SSID      "myssid"
#define EXAMPLE_ESP_WIFI_PASS      "12345678"
#define EXAMPLE_ESP_WIFI_CHANNEL   1
#define EXAMPLE_MAX_STA_CONN       4

#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR "192.168.4.2"
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif

#define PORT 8080

static const char *TAG = "tcp_client";
static const char *payload = "Message from ESP32C3 ";

static void tcp_client_task(void *pvParameters)
{
    char rx_buffer[128];
    char host_ip[] = HOST_IP_ADDR;
    int addr_family = 0;
    int ip_protocol = 0;

#if defined(CONFIG_EXAMPLE_IPV4)
        struct sockaddr_in dest_addr;
        dest_addr.sin_addr.s_addr = inet_addr(host_ip);
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(PORT);
        addr_family = AF_INET;
        ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)
        struct sockaddr_in6 dest_addr = { 0 };
        inet6_aton(host_ip, &dest_addr.sin6_addr);
        dest_addr.sin6_family = AF_INET6;
        dest_addr.sin6_port = htons(PORT);
        dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
        addr_family = AF_INET6;
        ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
        struct sockaddr_storage dest_addr = { 0 };
        ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif

    while (1) {

        int sock =  socket(addr_family, SOCK_STREAM, ip_protocol);
        if (sock < 0) {
            vTaskDelay(2000 / portTICK_PERIOD_MS);
            ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
            continue;
        }
        ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);

        int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
        if (err != 0) {
            vTaskDelay(2000 / portTICK_PERIOD_MS);
            ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
            continue;
        }
        ESP_LOGI(TAG, "Successfully connected");

        while (1) {
            int err = send(sock, payload, strlen(payload), 0);
            if (err < 0) {
                ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
                break;
            }

            int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
            // Error occurred during receiving
            if (len < 0) {
                ESP_LOGE(TAG, "recv failed: errno %d", errno);
                break;
            }
            // Data received
            else {
                rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
                ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
                ESP_LOGI(TAG, "%s", rx_buffer);
            }

            vTaskDelay(2000 / portTICK_PERIOD_MS);
        }

        if (sock != -1) {
            ESP_LOGE(TAG, "Shutting down socket and restarting...");
            shutdown(sock, 0);
            close(sock);
        }
    }
    vTaskDelete(NULL);
}


static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                                    int32_t event_id, void* event_data)
{
    if (event_id == WIFI_EVENT_AP_START){
        ESP_LOGI(TAG, "WIFI_EVENT_AP_START");
        xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
    } else if (event_id == WIFI_EVENT_AP_STACONNECTED) {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
                 MAC2STR(event->mac), event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
}

void wifi_init_softap(void)
{
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_ap();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));

    wifi_config_t wifi_config = {
        .ap = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
            .channel = EXAMPLE_ESP_WIFI_CHANNEL,
            .password = EXAMPLE_ESP_WIFI_PASS,
            .max_connection = EXAMPLE_MAX_STA_CONN,
            .authmode = WIFI_AUTH_WPA_WPA2_PSK,
            .pmf_cfg = {
                    .required = false,
            },
        },
    };
    if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}

void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    wifi_init_softap();  
}

三、工程调试

使用电脑连接ESP32C3的AP热点,并用网络调试助手开启一个TCP服务器,调试结果如下图:
在这里插入图片描述
打开服务器后客户端会自己连接上服务器并发送数据,服务器也可以发送数据给客户端。
关闭服务器后的现象如图:
在这里插入图片描述

总结

本次主要是实现ESP32C3的TCP客户端与服务器的通信,在实际的开发中也是客户端的使用场景较多。ESP32C3集成了强大的网络功能,我这目前也只是简单的应用。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ESP32C3的VScode IDE开发环境可以通过以下步骤进行搭建: 1. 首先,确保你已经安装了VScode编辑器,并在扩展商店中搜索并安装了"PlatformIO IDE"插件。 2. 打开VScode,点击左侧的"PlatformIO"图标,选择"PIO Home"。 3. 在PIO Home界面中,点击"New Project"创建一个新项目。 4. 在项目创建向导中,选择ESP32C3作为目标开发板,并选择合适的开发框架。 5. 在项目创建完成后,你可以在VScode的侧边栏中看到项目的文件结构。 6. 在项目文件夹中,你可以编写你的代码,并在VScode中进行编译、烧录和调试。 7. 如果你需要添加额外的库或者配置,请编辑项目的platformio.ini文件。 8. 最后,你可以使用VScode的调试功能来调试你的代码。 通过以上步骤,你就可以在VScode中搭建ESP32C3开发环境,并进行代码开发、编译、烧录和调试了。\[1\]\[2\]如果你需要下载ESP32C3开发发布链接,可以访问以下链接:https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json\[3\] #### 引用[.reference_title] - *1* *2* [ESP32C3学习&开发之路——VScode开发环境搭建](https://blog.csdn.net/RMDYBW/article/details/131476787)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [ESP32-C3开发之旅 基础篇② 如何安装ESP32-C3的Arduino VSCODE开发环境](https://blog.csdn.net/u011993802/article/details/123440228)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值