admin管理员组文章数量:1630195
一、前言
文章《ESP-12S学习⑤–Get拿天气数据》采用的就是TCP的连接方式,访问的是服务器,所以ESP8266做的是客户端
ESP8266可以扮演四种角色,分别是TCP客户端、TCP服务端、UDP客户端和UDP服务端
TCP客户端
相当于个人终端,比如手机电脑,这个时候对ESP8266的配置应该是配置为本地,手机开启TCP服务端,提供远端端口和ip
地址
ESP8266与手机的通讯流程:
ESP8266
连接WiFi- 定时器每隔
500ms
检测连接WiFi
状态是不是成功 - 如果连接成功,初始化
espconn
结构体(连接类型、远近ip
、远近端口),注册连接成功,重新连接等操作的回调函数 - 在成功连接的回调函数里面注册发送成功,接收成功,断开连接等操作的回调函数,并且调用
espconn_send
向服务端发送数据
只能在局域网内通信,手机和ESP8266连接同一个路由器
/******************************************/
os_timer_t ledtimer;
struct station_config wifi_config;
struct espconn pespconn;
const char remote_ip[4] = {192, 168, 1, 101}; // 手机的ip地址
/******************************************/
/**
* @name Sent_Data[发送、数据]
*/
void Sent_Data()
{
os_printf("connect succeed!!!\n");
espconn_regist_sentcb(&pespconn, Sent_Succeed); // 注册发送成功
espconn_regist_recvcb(&pespconn, Receive_Succeed); // 注册接收成功
espconn_regist_disconcb(&pespconn, Release_Succeed); // 注册断开
espconn_send(&pespconn, "Hello!", strlen("Hello!")); // 发送
}
/**
* @name Tcp_Disconect[TCP连接失败]
*/
void Tcp_Disconect(void *arg, sint8 err)
{
os_printf("Connect fail!!!\n");
os_printf("Reconnect!!!\n");
espconn_connect(&pespconn);
}
/**
* @name Sent_Succeed[数据发送成功]
*/
void Sent_Succeed()
{
os_printf("Send succeed!!!\n");
}
/**
* @name Receive_Succeed[接收成功]
*/
void Receive_Succeed(void *arg, char *pdata, unsigned short len)
{
os_printf("Receive succeed!!!\n");
os_printf("Data:%s\n", pdata); // 打印接收数据
}
/**
* @name Release_Succeed[TCP连接释放]
*/
void Release_Succeed()
{
os_printf("Release succeed!!!\n");
}
/**
* @name Espconn_Init[连接结构体初始化]
*/
void ICACHE_FLASH_ATTR Espconn_Init(ip_addr_t *remote_ip, int remote_port)
{
struct ip_info ststion_info;
wifi_get_ip_info(0x00, &ststion_info);
os_printf("init espconn struct!!!\n");
/*配置连接结构体*/
pespconn.type = ESPCONN_TCP;
pespconn.state = ESPCONN_NONE;
pespconn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp)); // 分配内存填充0
os_memcpy(pespconn.proto.tcp->local_ip, &ststion_info.ip, 4);
os_memcpy(pespconn.proto.tcp->remote_ip, remote_ip, 4);
pespconn.proto.tcp->local_port = espconn_port();
pespconn.proto.tcp->remote_port = remote_port;
/*注册*/
espconn_regist_connectcb(&pespconn, Sent_Data);
espconn_regist_reconcb(&pespconn, Tcp_Disconect);
/*连接服务器*/
os_printf("start connect!!!\n");
espconn_connect(&pespconn);
}
void ICACHE_FLASH_ATTR Check(void)
{
ip_addr_t addr;
struct espconn pespconn;
os_printf("Check!\n");
/*查询wifi的状态*/
if (wifi_station_get_connect_status() == STATION_GOT_IP)
{
os_timer_disarm(&ledtimer);
if (wifi_station_get_connect_status() == STATION_GOT_IP) // 再次确认
{
os_printf("succeed!\n");
os_printf("wifi_name:MST+QR\n");
Espconn_Init((struct ip_addr *)remote_ip, 10086); //给服务器端的ip和端口号,也就是手机开启的
}
}
else
{
os_printf("fail!\n");
}
}
/*
* @name: user_init[用户程序入口]
*/
void ICACHE_FLASH_ATTR
user_init(void)
{
system_timer_reinit();
uart_init(74880, 74880); //设置串口0和串口1的波特率
os_printf("SDK version:%s\n", system_get_sdk_version());
os_printf("Hello8266!\n");
wifi_set_sleep_type(NONE_SLEEP_T); // 关闭睡眠
// 设置wifi的工作模式
wifi_set_opmode(0x01); // Station模式
os_printf("Config!\n");
/*设置wifi密码名字*/
os_strcpy(wifi_config.ssid, "MST+QR");
os_strcpy(wifi_config.password, "123123123");
wifi_station_set_config(&wifi_config);
wifi_station_connect();
/*软件定时器*/
os_timer_disarm(&ledtimer); // 关闭定时器
os_timer_setfn(&ledtimer, (os_timer_func_t *)Check, (void*)0); // 设置定时器的回调函数
os_timer_arm_us(&ledtimer, 500000, 1); // 打开定时器,500ms,重复
}
配合上一节的SmartConfig
使用局域网通信
TCP服务端
可以理解为一个网关,发射热点
①:关于AP的配置
void ICACHE_FLASH_ATTR WiFi_Init(void)
{
// 设置wifi的工作模式
wifi_set_opmode(0x02); // AP模式
os_printf("APConfig!\n");
/*AP信息设置*/
ap_config.ssid_len = 12; // 根据自己的wifi名字长度来设置
os_strcpy(ap_config.ssid, "TP-LINK-8266"); // wifi名字
os_strcpy(ap_config.password, "82668266"); // wifi的密码
ap_config.channel = 1; // wifi通道1~13
ap_config.max_connection = 2; // 最大的连接数2
ap_config.beacon_interval = 100; // [信标间隔(认为是心跳就好了)](https://wwwblogs/zhanglinf/p/4584499.html)
ap_config.authmode = AUTH_WPA2_PSK; // 设置加密模式
ap_config.ssid_hidden = 0; // 不隐藏wifi
wifi_softap_set_config(&ap_config); // 设置并保存AP到flash
}
②:关于espconn的配置
ESP8266
做TCP Server
,不需要知道连接它的设备的ip
和端口,但是需要提供ip
和端口给需要连接的设备
void ICACHE_FLASH_ATTR Espconn_Init(int local_port)
{
os_printf("init espconn struct!!!\n");
/*配置连接结构体*/
pespconn.type = ESPCONN_TCP;
pespconn.state = ESPCONN_NONE;
pespconn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp)); // 分配内存填充0
pespconn.proto.tcp->local_port = local_port; // 设置一个端口(提供端口)
/*注册*/
espconn_regist_connectcb(&pespconn, Sent_Data);
espconn_regist_reconcb(&pespconn, Tcp_Disconect);
/*监听TCP服务器*/
os_printf("start connect!!!\n");
espconn_accept(&pespconn);
espconn_regist_time(&pespconn, 120, 0);
}
ip
地址自己会打印出来
ESP8266与手机的通讯流程:
- ESP8266发射热点,等待手机接入
/******************************************/
struct espconn user_tcp_espconn;
/******************************************/
/**
* @name Tcp_Disconect[TCP连接失败]
*/
void Tcp_Disconect(void *arg, sint8 err)
{
struct espconn *pespconn = arg;
os_printf("Connect fail!!!\n");
os_printf("Reconnect!!!\n");
espconn_connect(pespconn);
}
/**
* @name Sent_Succeed[数据发送成功]
*/
void Sent_Succeed(void *arg)
{
os_printf("Send succeed!!!\n");
}
/**
* @name Receive_Succeed[接收成功]
*/
void Receive_Succeed(void *arg, char *pdata, unsigned short len)
{
os_printf("Receive succeed!!!\n");
os_printf("Data:%s\n", pdata); // 打印接收数据
}
/**
* @name Release_Succeed[TCP连接释放]
*/
void Release_Succeed()
{
os_printf("Release succeed!!!\n");
}
/**
* @name Sent_Data[发送数据]
*/
void Sent_Data(void *arg)
{
os_printf("connect succeed!!!\n");
struct espconn *pespconn = arg;
espconn_regist_sentcb(pespconn, Sent_Succeed); // 注册发送成功
espconn_regist_recvcb(pespconn, Receive_Succeed); // 注册接收成功
espconn_regist_disconcb(pespconn, Release_Succeed); // 注册断开
espconn_send(pespconn, "Hello!", strlen("Hello!")); // 发送
}
/**
* @name Espconn_Init[连接结构体初始化]
*/
void ICACHE_FLASH_ATTR Espconn_Init(int local_port)
{
struct dhcps_lease please;
os_printf("init espconn struct!!!\n");
/*配置连接结构体*/
user_tcp_espconn.type = ESPCONN_TCP;
user_tcp_espconn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp)); // 分配内存填充0
user_tcp_espconn.proto.tcp->local_port = local_port;
/*注册*/
espconn_regist_connectcb(&user_tcp_espconn, Sent_Data);
espconn_regist_reconcb(&user_tcp_espconn, Tcp_Disconect);
/*监听TCP服务器*/
os_printf("start connect!!!\n");
espconn_accept(&user_tcp_espconn);
espconn_regist_time(&user_tcp_espconn, 120, 0);
}
void ICACHE_FLASH_ATTR WiFi_Init(void)
{
struct ip_info APip_info;
struct softap_config ap_config;
// 设置wifi的工作模式
wifi_set_opmode(0x02); // AP模式
os_printf("APConfig!\n");
/*AP信息设置*/
ap_config.ssid_len = 12;
os_strcpy(ap_config.ssid, "TP-LINK-8266");
os_strcpy(ap_config.password, "82668266");
ap_config.channel = 1;
ap_config.max_connection = 2;
ap_config.beacon_interval = 100;
ap_config.authmode = AUTH_WPA2_PSK; //设置加密模式
ap_config.ssid_hidden = 0;
wifi_softap_set_config(&ap_config); // 设置并保存AP
}
/*
* @name: user_init[用户程序入口]
*/
void ICACHE_FLASH_ATTR
user_init(void)
{
system_timer_reinit();
uart_init(74880, 74880); //设置串口0和串口1的波特率
os_printf("SDK version:%s\n", system_get_sdk_version());
os_printf("Hello8266!\n");
os_printf("**************************************************\n");
WiFi_Init();
Espconn_Init(10086);
}
UDP客户端
UDP
客户端与UDP
服务端通信是不需要建立连接的,虽然是不建立连接,但是还是需要知道目的地址和端口号,UDP
可以发广播,发广播使用的地址是255.255.255.255
ESP8266
有两种方式和手机的UDP Server
通信,一个是通过广播,二个是通过手机的ip
地址,有什么区别呢
* 如果手机是连接着路由器的,那么ESP8266
就没有办法通过广播地址和手机UDP Server
通信,这是不允许的
ESP8266
是可以通过广播跟连接着路由器的手机通信的2020.6.22补
- 如果
ESP8266
是直接连接手机的,那么ESP8266
就可以通过广播地址和手机ip
与手机UDP Server
通信
os_timer_t ledtimer;
/******************************************/
struct station_config wifi_config;
struct espconn pespconn;
char remote_ip[4] = {192, 168, 1, 102};
/******************************************/
/**
* @name Sent_Succeed[数据发送成功]
*/
void Sent_Succeed(void *arg)
{
os_printf("Send succeed!!!\n");
}
/**
* @name Receive_Succeed[接收成功]
*/
void Receive_Succeed(void *arg, char *pdata, unsigned short len)
{
os_printf("Receive succeed!!!\n");
os_printf("Data:%s\n", pdata); // 打印接收数据
espconn_send((struct espconn *)arg, "Hello", strlen("Hello"));
}
/**
* @name Espconn_Init[连接结构体初始化]
*/
void ICACHE_FLASH_ATTR Espconn_Init(ip_addr_t *remote_ip, int local_port, int remote_port)
{
os_printf("init espconn struct!!!\n");
// wifi_set_broadcast_if(0x01);
/*配置连接结构体*/
pespconn.type = ESPCONN_UDP;
pespconn.state = ESPCONN_NONE;
pespconn.proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp)); // 分配内存填充0
os_memcpy(pespconn.proto.udp->remote_ip, remote_ip, 4); // 目的地址广播
pespconn.proto.udp->local_port = local_port;
pespconn.proto.udp->remote_port = remote_port;
/*注册*/
espconn_regist_recvcb(&pespconn, Receive_Succeed); // 注册接收成功
espconn_regist_sentcb(&pespconn, Sent_Succeed); // 注册发送成功
/*连接服务器*/
os_printf("UDP create!!!\n");
espconn_create(&pespconn);
espconn_send(&pespconn, "Hello", strlen("Hello"));
}
void ICACHE_FLASH_ATTR Check(void)
{
ip_addr_t addr;
struct espconn pespconn;
os_printf("Check!\n");
/*查询wifi的状态*/
if (wifi_station_get_connect_status() == STATION_GOT_IP)
{
os_timer_disarm(&ledtimer);
if (wifi_station_get_connect_status() == STATION_GOT_IP) // 再次确认
{
os_printf("succeed!\n");
os_printf("wifi_name:MST+QR\n");
Espconn_Init((struct ip_addr *)remote_ip, 10000, 10086); //给服务器端的ip和端口号,也就是手机开启的
}
}
else
{
os_printf("fail!\n");
}
}
/*
* @name: user_init[用户程序入口]
*/
void ICACHE_FLASH_ATTR
user_init(void)
{
system_timer_reinit();
uart_init(74880, 74880); //设置串口0和串口1的波特率
os_printf("SDK version:%s\n", system_get_sdk_version());
os_printf("Hello8266!\n");
wifi_set_sleep_type(NONE_SLEEP_T); // 关闭睡眠
// 设置wifi的工作模式
wifi_set_opmode(0x01); // Station模式
os_printf("Config!\n");
/*设置wifi密码名字*/
os_strcpy(wifi_config.ssid, "MST+QR");
os_strcpy(wifi_config.password, "123123123");
wifi_station_set_config(&wifi_config);
wifi_station_connect();
/*软件定时器*/
os_timer_disarm(&ledtimer); // 关闭定时器
os_timer_setfn(&ledtimer, (os_timer_func_t *)Check, (void*)0); // 设置定时器的回调函数
os_timer_arm_us(&ledtimer, 500000, 1); // 打开定时器,500ms,重复
}
不知道为什么,手机端是可以接收到ESP8266
信息的,但是手机没有办法发送信息给ESP8266
UDP服务端
某种意义上无法明确区分UDP服务器端和UDP客户端
配置wifi热点:
还是和上面的TCP服务器模式一致
void ICACHE_FLASH_ATTR WiFi_Init(void)
{
struct ip_info APip_info;
// 设置wifi的工作模式
wifi_set_opmode(0x02); // AP模式
os_printf("APConfig!\n");
/*AP信息设置*/
ap_config.ssid_len = 12;
os_strcpy(ap_config.ssid, "TP-LINK-8266");
os_strcpy(ap_config.password, "82668266");
ap_config.channel = 1;
ap_config.max_connection = 2;
ap_config.beacon_interval = 100;
ap_config.authmode = AUTH_WPA2_PSK; //设置加密模式
ap_config.ssid_hidden = 0;
wifi_softap_set_config(&ap_config); // 设置并保存AP
}
初始化UDP连接结构体:
设置两个端口,注册接收回调函数,还是用espconn_regist_recvcb()
注册
void ICACHE_FLASH_ATTR Espconn_Init(int local_port, int remote_port, struct ip_addr *remote_ip)
{
os_printf("init espconn struct!!!\n");
/*配置连接结构体*/
pespconn.type = ESPCONN_UDP;
pespconn.state = ESPCONN_NONE;
pespconn.proto.udp = (esp_udp *) os_zalloc(sizeof(esp_udp)); // 分配内存填充0
pespconn.proto.udp->remote_port = remote_port;
pespconn.proto.udp->local_port = local_port;
// memcpy(pespconn.proto.udp->remote_ip, remote_ip, 4);
espconn_regist_recvcb(&pespconn, Receive_Function); //接收
os_printf("UDP start !!!\n");
espconn_create(&pespconn); // 创建UDP连接
}
接收回调函数:
void Receive_Function(void *arg, char *pdata, unsigned short len)
{
sint16 ret;
os_printf("Receive:%s\r\n", pdata);
espconn_sent((struct espconn *) arg, "ok", strlen("ok"));
ret = espconn_sendto((struct espconn *) arg, "Hello", strlen("Hello"));
os_printf("ret:%d\n", ret);
}
同样的,手机端总是接收不到 ,手机端需要填写ESP8266
发过来的信息,但是手机端是可以发送信息的ESP8266
端的ip
地址和端口号,ip
地址可以写确定的ESP8266
地址,也可以写广播地址255.255.255.255
那个单方向传输的问题先放着吧,不知道怎么回事
2020.6.4
TCP服务器的总代码修改了,struct espconn user_tcp_espconn;
这里面的user_tcp_espconn
最好和后面的注册函数的区分开来,注册函数是有传参的,但是我写的是没有传参的,导致没有办法接收到信息,其他的几个也应该是这样,但是我这里没有修改
2020.6.19
本文标签: 服务端客户端espudpESP8266TCP
版权声明:本文标题:ESP-12S学习(7)--ESP8266TCP和UDP的客户端和服务端 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1729027167a1183386.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论