ESP32-C3, esp-idf 4.3.5,tcp client 非阻塞式循环收发,提供一个例程
时间: 2024-01-01 21:10:21 浏览: 336
乐鑫Esp32学习 esp32上实现本地 TCP 客户端和服务端角色,可断线重连原路返回数据。
3星 · 编辑精心推荐
好的,下面是一个基于ESP32-C3和esp-idf 4.3.5的tcp client非阻塞式循环收发的例程:
```c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_system.h"
#include "esp_event_loop.h"
#include "esp_timer.h"
#define WIFI_SSID "your_ssid"
#define WIFI_PASS "your_password"
#define SERVER_IP "192.168.1.100"
#define SERVER_PORT 8888
#define TAG "TCP_CLIENT"
static int s_retry_num = 0;
static bool s_connected = false;
static int s_socket = -1;
static esp_netif_t *s_wifi_netif = NULL;
static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < 5) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
}
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
ESP_LOGI(TAG, "got ip:%s",
ip4addr_ntoa(&event->ip_info.ip));
s_retry_num = 0;
s_connected = true;
}
}
static void tcp_client_task(void *pvParameters)
{
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
server_addr.sin_port = htons(SERVER_PORT);
while(1) {
if (!s_connected) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
if (s_socket == -1) {
s_socket = socket(AF_INET, SOCK_STREAM, 0);
if (s_socket < 0) {
ESP_LOGE(TAG, "failed to create socket");
s_connected = false;
continue;
}
if (connect(s_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) {
ESP_LOGE(TAG, "failed to connect to server");
close(s_socket);
s_socket = -1;
s_connected = false;
continue;
}
ESP_LOGI(TAG, "connected to server");
}
char send_buf[64] = "hello";
int send_len = strlen(send_buf);
int sent_len = send(s_socket, send_buf, send_len, 0);
if (sent_len != send_len) {
ESP_LOGE(TAG, "failed to send data");
close(s_socket);
s_socket = -1;
s_connected = false;
continue;
}
char recv_buf[64] = {0};
int recv_len = recv(s_socket, recv_buf, sizeof(recv_buf), MSG_DONTWAIT);
if (recv_len < 0 && errno != EAGAIN) {
ESP_LOGE(TAG, "failed to receive data");
close(s_socket);
s_socket = -1;
s_connected = false;
continue;
} else if (recv_len > 0) {
ESP_LOGI(TAG, "received data: %s", recv_buf);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main()
{
ESP_ERROR_CHECK(esp_netif_init());
s_wifi_netif = esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
},
};
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL));
xTaskCreate(tcp_client_task, "tcp_client_task", 4096, NULL, 5, NULL);
}
```
这个例程中,我们使用了ESP-IDF提供的API来连接WiFi、创建socket、发送和接收数据等操作。`tcp_client_task`函数是一个无限循环的任务,它会在连接上WiFi后不断发送和接收数据。如果连接断开了,它会尝试重新连接。注意,在发送和接收数据时,我们使用了非阻塞式的方式,并且使用了`MSG_DONTWAIT`标志和`errno`变量来判断是否有数据可以读取或者是否发生了错误。
需要注意的是,这个例程中的WiFi和服务器的IP地址、端口号等参数需要根据实际情况进行修改。同时,如果你的服务器是在局域网内的,需要保证ESP32-C3和服务器在同一个局域网内。
阅读全文