ESP8266之TCP_Client
模块:esp-01s
SDK版本:ESP8266_RTOS_SDK-3.0
开发环境:wsl+vscode
功能模块:wifi,tcp_client
由于esp8266 sdk 2.0以后的版本似乎去掉了“espconn.h”头文件,网上的很多程序不能用了,官方文档也没跟得上sdk的更新速度,我们只能通过socket来实现tcp通信了。
关于socket基本知识,有一篇文章解释的比较清楚 Linux Socket编程(不限Linux)
本文代码tcp部分参考了 ESP8266_RTOS_SDK V3.0下TCP 通讯
本程序能够完成wifi重连,tcp断开重连,稳定可靠!
2018.9.30更新:解决了wifi断开后tcp不能重连的问题
编译基于ESP8266 RTOS SDK V3.0,由于sdk不断更新,不保证其他版本sdk能够使用
8266作为tcp client,连接到局域网的tcp server
#include<stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "rom/ets_sys.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#define STA_SSID "esp_test"
#define STA_PASS "12345678"
#define PORT_ADDR "192.168.1.243"
static EventGroupHandle_t wifi_event_group;
const int CONNECTED_BIT = BIT0;
static void http_get_task(void *pvParameters);
static const char *TAG = "example";
//wifi的回调事件注册
//static EventGroupHandle_t wifi_event_group;
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
//station模式下开始连接
case SYSTEM_EVENT_STA_START:
printf("开始连接wifi\n");
esp_wifi_connect();
break;
//station模式下已完成连接并且获取到了IP
case SYSTEM_EVENT_STA_GOT_IP:
//将其ip信息打印出来
printf("获取到IP:%s\n",ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
break;
//station模式下 本设备从AP断开/AP踢了本设备
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();//重新连接之前的AP
break;
default:
break;
}
return ESP_OK;
}
void wifi_init_sta(void)
{
//开始wifi 连接
//wifi_event_group = xEventGroupCreate(); //创建一个事件组
tcpip_adapter_init(); //初始化TCP/IP相关,这个函数只需要调用一次
esp_event_loop_init(event_handler, NULL); //注册事件
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg); //初始化wifi底层相关
//构造需要连接的wifi信息
wifi_config_t wifi_config = {
.sta = {
.ssid = STA_SSID, //填入wifi名称/ssid
.password = STA_PASS //填入wifi密码
},
};
esp_wifi_set_mode(WIFI_MODE_STA); //设置wifi模式,设置为station模式
esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config); //将其wifi信息配置进去
esp_wifi_start(); //开启wifi状态机 ()
}
static void http_get_task(void *pvParameters)
{
char *servInetAddr = PORT_ADDR;
struct sockaddr_in sockaddr;
char recvline[64];
char sendline[64]="hello world\n";
while(1)
{
int s = socket(AF_INET, SOCK_STREAM, 0);//2,1,0
if(s < 0) {
printf("Socket failed:%d\n",s);
close(s);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
memset(&sockaddr,0,sizeof(sockaddr));
sockaddr.sin_family = AF_INET; //设定为ipv4
sockaddr.sin_port = htons(60000); //设定端口号
inet_pton(AF_INET,servInetAddr,&sockaddr.sin_addr);
if((connect(s,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) < 0 )
{
printf("Socket connect failed!\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
if (write(s, sendline, strlen(sendline)) < 0) {
printf("Socket send failed\n");
close(s);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
while(1)
{
// memset(&recvline,0,sizeof(recvline));
int iDataNum= recv(s,recvline,64,0);
if(iDataNum>0){
// recvline[iDataNum]='\0';
recvline[iDataNum]='\0';
printf("%s\n",recvline); //接收到的数据
}else if(iDataNum==0||get_wifi_status()==false)
{
//服务端或本地段意外/手动断开
close(s);
break;
//跳出接收循环这样完成自动重连
}
}
}
}
void app_main(void)
{
// uart_set_baudrate(0,115200);//将串口设置成115200
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
printf("SDK version:%s\n", esp_get_idf_version());
printf("ESP_WIFI_MODE_STA");// 打印当前模式
wifi_init_sta();//station模式初始化
//vTaskDelay(10000 / portTICK_PERIOD_MS);
xTaskCreate(&http_get_task, "http_get_task", 16384, NULL, 5, NULL);
}