乐鑫Esp32学习之旅⑨ esp32上实现本地 TCP 客户端和服务端角色,可断线重连原路返回数据。(附带Demo)

Posted 半颗心脏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了乐鑫Esp32学习之旅⑨ esp32上实现本地 TCP 客户端和服务端角色,可断线重连原路返回数据。(附带Demo)相关的知识,希望对你有一定的参考价值。


  • 本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途。如有不对之处,请留言,本人及时更改。

1、 爬坑学习新旅程,虚拟机搭建esp32开发环境,打印 “Hellow World”。
2、 巧用eclipes编辑器,官方教程在在Windows下搭建esp32开发环境,打印 “Hellow World”。
3、 认识基本esp32的GPIO接口,开始点亮您的第一盏 LED和中断回调实现按键功能 。
4、体会esp32的强大的定时器功能, 实现定时2s闪烁一盏LED灯。
5、接触实践esp32的pwm宽度脉冲功能, 实现呼吸效果闪烁一盏LED灯。
6、smartConfig和微信airKiss在esp32的实现,一键配网轻松快捷连接路由器。
7、利用GPIO中断做一个按键的短按和长按的回调事件,再也无须担心触发源。
8、esp32上实现本地 UDP 客户端和服务端角色,在局域网内实现通讯。
9、esp32上实现本地 TCP 客户端和服务端角色,可断线重连原路返回数据。
10、乐鑫esp32 SDK编程利用rmt驱动ws2812七彩灯,实现彩虹渐变效果。
11、入门 乐鑫esp-adf 音频框架开发,esp32造一个蓝牙耳机,实现切换歌曲,获取歌曲信息等功能。
12、开源一个微信公众号airkiss配网esp32以及局域网发现功能的工程,分享一个airkiss配网小工具。
13、esp32 内置 dns 服务器,无需外网访问域名返回指定网页。
14、esp32 sdk编程实现门户强制认证,连接esp32热点之后,自动强制弹出指定的登录界面。
15、认识本地离线语音唤醒识别框架 esp-skainet ,实现较低成本的硬件语音本地识别控制。
16、学习本地语音唤醒离线识别框架 esp-skainet ,如何修改唤醒词? 如何自定义命令词?如何做意图动作?
17、全网首发,乐鑫esp32 sdk直连京东微联·小京鱼 · IoT开放平台,实现叮咚音响语音智能控制。
18、入门京东微联·小京鱼的控制面板H5开发,读懂vue语法,做自己的控制页面。
19、重磅开源,如何在微信小程序上ble蓝牙配网esp32,blufi的那些事!
20、一篇好文,开发过程中编译esp32固件太大,无法正常启动?教你如何自定义分区表partitions.csv。


文章目录

本篇博文目录:

文章目录

一. 前言;


  • 2018年的高考分数线出来了,广东省的本科的理科分数线 375分,貌似比当年2014年高考低好多啊。。哈哈!

  • 回归正题,TCP基本协议,我就不多说了,可以看看我的前面的8266系列的,本博文通讯框架基于lwip,主要修改实现以下功能:

  • TCP服务端时候,客户端连接进来的数据原路返回,而且断开连接之后,允许重新连接。

  • TCP客户端时候,设置每三秒向服务器发送数据!


二. 服务端;


  • 左边是 visual studio code编译器的终端显示esp32显示打印的数据,右边是手机通讯调试助手。

2.1 实现的过程:

  • 首先根据配置信息来开启热点模式,等待设备的连接。
  • 设备连接成功后,开启TCP server服务器端,然后通讯!
  • 注意的是:当前的网关的IP地址就是服务器地址,默认是192.168.4.1这个是乐鑫在出厂时候写死的!知道就好!

2.2 核心的代码:


  • ①:创建热点(和上篇的UDP一样):
void wifi_init_softap()

    tcp_event_group = xEventGroupCreate();

    tcpip_adapter_init();
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    wifi_config_t wifi_config = 
        .ap = 
            .ssid = SOFT_AP_SSID, //设置名字
            .ssid_len = 0,
            .max_connection = SOFT_AP_MAX_CONNECT, //最大连接数目
            .password = SOFT_AP_PAS, //密码
            .authmode = WIFI_AUTH_WPA_WPA2_PSK,//加密方式
    ;
    if (strlen(EXAMPLE_DEFAULT_PWD) == 0)//如果密码为空,则设置开放性wifi热点
    
        wifi_config.ap.authmode = WIFI_AUTH_OPEN; 
    

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

    ESP_LOGI(TAG, "SoftAP set finish:%s pas:%s \\n",EXAMPLE_DEFAULT_SSID, EXAMPLE_DEFAULT_PWD);


  • ②:创建TCP服务器,等待客户端连接:

//形参的含义:true为创建服务器并且等待连接,false仅仅只是等待连接;返回值是是否成功接收到一个设备的连接
esp_err_t create_tcp_server(bool isCreatServer)


    if (isCreatServer)
    
        ESP_LOGI(TAG, "server socket....,port=%d\\n", TCP_PORT);
        server_socket = socket(AF_INET, SOCK_STREAM, 0);

        if (server_socket < 0)
        
            show_socket_error_reason("create_server", server_socket);
            return ESP_FAIL;
        

        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(TCP_PORT);//指定的端口号
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

        //开始创建
        if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
        
            show_socket_error_reason("bind_server", server_socket);
            close(server_socket);
            return ESP_FAIL;
        
    

    //监听指定的端口
    if (listen(server_socket, 5) < 0)
    
        show_socket_error_reason("listen_server", server_socket);
        close(server_socket);
        return ESP_FAIL;
    

    connect_socket = accept(server_socket, (struct sockaddr *)&client_addr, &socklen);
    //判断是否连接成功
    if (connect_socket < 0)
    
        show_socket_error_reason("accept_server", connect_socket);
        close(server_socket);
        return ESP_FAIL;
    

    /*connection established,now can send/recv*/
    ESP_LOGI(TAG, "tcp connection established!");
    return ESP_OK;


  • ③:接收数据:
void recv_data(void *pvParameters)

    int len = 0;
    char databuff[1024];
    while (1)
    
     while (1)  
            //每次接收都要清空接收数组
            memset(databuff, 0x00, sizeof(databuff));
            len = recv(connect_socket, databuff, sizeof(databuff), 0);
            //打印接收到的数组
            ESP_LOGI(TAG, "recvData: %s\\n", databuff);
            //原路返回,不指定某个客户端
            send(connect_socket, databuff , sizeof(databuff), 0);
        if (len > 0) 
                g_total_data += len;
                g_rxtx_need_restart = false;
             else 
                show_socket_error_reason("recv_data", connect_socket);
                g_rxtx_need_restart = true;
            
        
    
    g_rxtx_need_restart = true;
    vTaskDelete(NULL);


2.3 注意问题:


  • 虽然乐鑫也提供了TCP的例程,但是发现是当客户端断开连接之后再次连接时候,客户端提示已经连接成功,但发现服务器并没有去监听这个设备的信息,原因在于没有去等待监听,还是要通过listen()accept()方法来获取一个远程的设备地址。

三. TCP Client客户端;


  • 下图可以看到,服务器的地址为192.168.1.104,端口:8266 ,此配置信息可在demo里面的头文件修改!

  • 发送数据原路返回和上面的服务器代码一样,只是当与服务器断开连接时候,需要关闭socket重新连接,而我们的服务器是不需要关闭socket只是继续等待客户端连接,这一点需要注意!


3.1 实现的过程:

  1. 上电开启station模式来连接指定的路由器,连接成功之后创建socket连接tcp server服务器。
  2. 连接成功后,需要开启收发的任务,并且在收到数据之后原路返回。
  3. 如果连接成功之后,服务器突然断开,那么esp32需要断开socket,毕竟服务器已经断开,留着也没用,之后尝试重新创建socket来连接服务器,直到成功为止!

3.2 核心代码:

  • ① 连接指定的路由器:
void wifi_init_sta()

    tcp_event_group = xEventGroupCreate();

    tcpip_adapter_init();
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    wifi_config_t wifi_config = 
            .sta = 
            .ssid = GATEWAY_SSID, //路由器名字
            .password = GATEWAY_PAS,//路由器密码
    ;
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
    ESP_LOGI(TAG, "wifi_init_sta finished.");
    ESP_LOGI(TAG, "connect to ap SSID:%s password:%s \\n",
             GATEWAY_SSID, GATEWAY_PAS);

  • ② 创建客户端并且指定连接到服务器端:
//创建TCP客户端连接到指定的服务器
esp_err_t create_tcp_client()


    ESP_LOGI(TAG, "will connect gateway ssid : %s port:%d\\n",
             TCP_SERVER_ADRESS, TCP_PORT);

    connect_socket = socket(AF_INET, SOCK_STREAM, 0);

    if (connect_socket < 0)
    
        show_socket_error_reason("create client", connect_socket);
        return ESP_FAIL;
    
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(TCP_PORT);
    server_addr.sin_addr.s_addr = inet_addr(TCP_SERVER_ADRESS);
    ESP_LOGI(TAG, "connectting server...");
    if (connect(connect_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    
        show_socket_error_reason("client connect", connect_socket);
        ESP_LOGE(TAG, "connect failed!");
        return ESP_FAIL;
    
    ESP_LOGI(TAG, "connect success!");
    return ESP_OK;


demo的配置信息:

  • 下面的配置宏定义需要在头文件修改!
//true为开启热点并且创建tcp服务器,fasle为连接到指定的路由器并且连接到指定的tcp服务器
#define TCP_SERVER_CLIENT_OPTION FALSE 
//打印的tag
#define TAG "XuHongTCP-->" 

//以下是softAP热点模式的配置信息
#define SOFT_AP_SSID "XuHongTCP2018"
#define SOFT_AP_PAS "xuhong123456" //如果密码设置为空,则配置的热点是开放的,没有密码的。
#define SOFT_AP_MAX_CONNECT 1 //作为AP热点时候,最大的连接数目


//以下是station模式配置信息,是您家里的路由器的信息
#define GATEWAY_SSID "AliyunOnlyTest"
#define GATEWAY_PAS "aliyun#123456"
#define TCP_SERVER_ADRESS "192.168.1.104" //要连接TCP服务器地址
//统一的端口号,包括TCP客户端或者服务端
#define TCP_PORT 8266

五 下载:

  • 注意运行demo前务必要修改配置信息,保证路由器名字密码正确!
  • 本博文硬件代码下载:https://download.csdn.net/download/xh870189248/10502414
  • esp32汇总工程,欢迎star,收到第一更新信息:https://github.com/xuhongv/StudyInEsp32

以上是关于乐鑫Esp32学习之旅⑨ esp32上实现本地 TCP 客户端和服务端角色,可断线重连原路返回数据。(附带Demo)的主要内容,如果未能解决你的问题,请参考以下文章

乐鑫Esp32学习之旅28 分享在 esp32 SDK实现驱动 Flash W25Q32 的封装,扩大容量存储更多的资源。(开源源码工程)。

乐鑫Esp32学习之旅 乐鑫 ESP-S2/S3 模组的实现 USB 无线网卡上网,为你的台式机装上无线WiFI上网吧。(附带源码)

乐鑫Esp32学习之旅 乐鑫 ESP-S2/S3 模组的实现 USB 无线网卡上网,为你的台式机装上无线WiFI上网吧。(附带源码)

乐鑫Esp32学习之旅 乐鑫 ESP-S2/S3 模组的实现 USB 无线网卡上网,为你的台式机装上无线WiFI上网吧。(附带源码)

乐鑫Esp32学习之旅28 分享在 esp32 SDK实现驱动 Flash W25Q32 的封装,扩大容量存储更多的资源。(开源源码工程)。

乐鑫Esp32学习之旅28 分享在 esp32 SDK实现驱动 Flash W25Q32 的封装,扩大容量存储更多的资源。(开源源码工程)。