乐鑫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

  • 9
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半颗心脏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值