《ESP-IDF入门指南》----->LwIP(tcp client 通信)
一名在校学生,不定时分享和总结一些嵌入式和物联网相关的知识,欢迎大家提出关于本文章相关意见。
简介
ESP-IDF 使用开源的LwIP轻量级TCP/IP协议栈
,并在原始的LwIP上做了修改和补充。
支持的API:
- BSD套接字API。
- Netconn API 已启用,但暂无对 ESP-IDF 应用程序的官方支持。
warning:
- 在使用除BSD套接字API以外的任意 lwIP API 时,请确保所用 API 为线程安全。请启用 CONFIG_LWIP_CHECK_THREAD_SAFETY 配置选项并运行应用程序,检查所用 API 是否线程安全。
- lwIP 断言 TCP/IP 核心功能可以正确访问。如果未能从正确的 lwIP FreeRTOS 任务 访问,或没有正确锁定,则执行中止。
- 建议使用 ESP-NETIF 组件与 lwIP 交互。
注:
BSD套接字
:(伯克利套接字 Internet Berkeley sockets) API是一种应用程序接口(API),用于网络套接字( socket)与Unix域套接字,包括了一个用C语言写成的应用程序开发库,主要用于实现进程间通讯,在计算机网络通讯方面被广泛使用。
NetconnAPI
:是lwIP协议栈提供的一套方便易用的网络编程接口。
BSD套接字API
-
socket()
-
bind()
-
accept()
-
shutdown()
-
getpeername()
-
getsockopt()
和setsockopt()
:请参阅 套接字选项 -
close()
: -
read()
、readv()
、write()
、writev()
: -
recv()
、recvmsg()
、recvfrom()
-
send()
、sendmsg()
、sendto()
-
select()
: -
poll()
:ESP-IDF 通过在内部调用select()
实现poll()
,因此,建议直接调用select()
-
fcntl()
:非标准函数:
ioctl()
:
应用实例
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "lwip/sockets.h"
//print information symbol
const static char* TAG="MYWIFI";
//create two task handle with taskNotify function
TaskHandle_t task1;
TaskHandle_t task2;
/*
*********************************************************************************************************
* 函 数 名: event_handler
* 功能说明: wifi and ip event
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void 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_LOGI(TAG, "wifi connecting\n");
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
ESP_LOGI(TAG, "wifi connected\n");
vTaskDelay(500);
ESP_LOGI(TAG, "wifi connecting\n");
esp_wifi_connect();
} 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:" IPSTR, IP2STR(&event->ip_info.ip));
xTaskNotifyGive(task2);
}
}
/*
*********************************************************************************************************
* 函 数 名: my_wifi_nvs_flash_init
* 功能说明: init nvs-flash
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void my_wifi_nvs_flash_init()
{
esp_err_t err=ESP_OK;
err=nvs_flash_init();
if(err!=ESP_OK){
ESP_ERROR_CHECK(nvs_flash_erase());
nvs_flash_init();
}
}
/*
*********************************************************************************************************
* 函 数 名: my_wifi_netif_event_config
* 功能说明: init netif and event
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void my_wifi_netif_and_event_config()
{
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
}
void my_wifi_wifi_init(void* param)
{
my_wifi_nvs_flash_init();
my_wifi_netif_and_event_config();
wifi_init_config_t cfg=WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
const wifi_config_t conf={
.sta={
.ssid="",//wifi id
.password=""//wifi password
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA,&conf));
ESP_ERROR_CHECK(esp_wifi_start());
vTaskDelete(NULL);
}
void tcp_client_task(void* param){
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
int sock;
while(1){
sock=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if(sock<0){
ESP_LOGE("TAG","socket connect is error\n");
}
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr("");//ip地址
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(8080);//端口号
int err=connect(sock,&dest_addr,sizeof(struct sockaddr));
if(err!=0){
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
}
while (1) {
char* msg="message from esp32";
int err = send(sock, msg, strlen(msg), 0);
if (err < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break;
}
char rex_buf[100];
//默认情况下,该函数会进行阻塞.
//ret = lwip_recv_tcp(sock, mem, len, flags);在这个函数中进行阻塞.
//如果将flags==MSG_DONTWAIT则非阻塞
err=recv(sock, rex_buf, sizeof(rex_buf) - 1,MSG_DONTWAIT);
if(err>=0){
rex_buf[err]=0;
printf("received message:%s\n",rex_buf);
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
if (sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
}
}
}
void app_main(void)
{
xTaskCreate(my_wifi_wifi_init, "wifi connect", 4096, NULL, 5, &task1);
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, &task2);
}
参考文档
- (https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32/api-guides/lwip.html#bsd-api)