ESP8266例程解析⑥TCP server and client

一、简介

  1. 在网络传输应用层中,通常使用TCP和UDP这三种协议实现数据的传输。在传输过程中,需要双向的通讯连接实现数据的交互。因此,在这双向链路的一端称之为socket,一个socket有一个IP地址和端口号。
  2. 目前流程的网络编程模型是客户端/服务端(C/S)结构。
  3. TCP是Transmission Control Protocol的简称,是一个可靠的面向链接的协议,一旦成功建立连接,保证了数据的完整性传到目的地!
  4. TCP好像打电话,双方要通话,首先,要确定对方不是开机(网络可以到达),然后要确定是不是没有信号(),然后还需要对方接听(通信链接)。
  5. TCP要等待对面的确认,方可建立连接。也就是人们所说的“三次握手”,但是执行效率较慢,但是安全可靠,毕竟人家是保证了数据的完整性!

二、TCP server and client

TCP server(手机为TCP客户端,8266为TCP服务端)

提示:
ESP8266充当服务端时候,要自身开启WIFI热点,等待设备接入,好比一个网关。手机接入8266热点WiFi时候,注意串口发出来的IP地址,此地址是手机要连接的服务端的地址。注意好串口号即可通讯,此通讯100%保证到达目的地。

TCP server流程分析 (即代码分析)

  1. 8266分区初始化
  2. 串口初始化
  3. WiFi设置模式(0X02 soft-AP 模式)
  4. esp8266 soft-AP 初始化并使能
  5. TCP准备(给本地端口8266,分配空间,设置协议,注册TCP连接成功,并且回调函数(接收 发送 断开) 注册 TCP连接发生异常断开时的回调函数(可以在回调函数中进行重连,并打印错误代码) 创建 TCP server,建立侦听 设置超时断开时间)

代码

#include "driver/uart.h"  //串口0需要的头文件
#include "osapi.h"  //串口1需要的头文件
#include "user_interface.h" //WIFI连接需要的头文件
#include "espconn.h"//TCP连接需要的头文件
#include "mem.h" //系统操作需要的头文件
#include "gpio.h"

struct espconn user_tcp_espconn;

void ICACHE_FLASH_ATTR server_recv(void *arg, char *pdata, unsigned short len) 
{
	os_printf("收到PC发来的数据:%s", pdata);
	espconn_sent((struct espconn *) arg, "收到!", strlen("收到!"));

}
void ICACHE_FLASH_ATTR server_sent(void *arg) 
{
	os_printf("发送成功!");
}
void ICACHE_FLASH_ATTR server_discon(void *arg) 
{
	os_printf("连接已经断开!");
}

void ICACHE_FLASH_ATTR server_listen(void *arg)  //注册 TCP 连接成功建立后的回调函数
{
	struct espconn *pespconn = arg;
	espconn_regist_recvcb(pespconn, server_recv);  //接收
	espconn_regist_sentcb(pespconn, server_sent);  //发送
	espconn_regist_disconcb(pespconn, server_discon);  //断开
}
void ICACHE_FLASH_ATTR server_recon(void *arg, sint8 err) //注册 TCP 连接发生异常断开时的回调函数,可以在回调函数中进行重连
{
	os_printf("连接错误,错误代码为:%d\r\n", err); //%d,用来输出十进制整数
}

void Inter213_InitTCP(uint32_t Local_port)
 {
	user_tcp_espconn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp)); //分配空间
	user_tcp_espconn.type = ESPCONN_TCP; //设置类型为TCP协议
	user_tcp_espconn.proto.tcp->local_port = Local_port; //本地端口

	espconn_regist_connectcb(&user_tcp_espconn, server_listen); //注册 TCP 连接成功建立后的回调函数
	espconn_regist_reconcb(&user_tcp_espconn, server_recon); //注册 TCP 连接发生异常断开时的回调函数,可以在回调函数中进行重连
	espconn_accept(&user_tcp_espconn); //创建 TCP server,建立侦听
	espconn_regist_time(&user_tcp_espconn, 180, 0); //设置超时断开时间 单位:秒,最大值:7200 秒

}

void WIFI_Init()
 {
	struct softap_config apConfig;
	wifi_set_opmode(0x02);    //设置为AP模式,并保存到 flash
	apConfig.ssid_len = 8;						//设置ssid长度
	os_strcpy(apConfig.ssid, "xiaofang");	    //设置ssid名字
	os_strcpy(apConfig.password, "12345678");	//设置密码
	apConfig.authmode = 3;                      //设置加密模式
	apConfig.beacon_interval = 100;            //信标间隔时槽100 ~ 60000 ms
	apConfig.channel = 1;                      //通道号1 ~ 13
	apConfig.max_connection = 4;               //最大连接数
	apConfig.ssid_hidden = 0;                  //隐藏SSID

	wifi_softap_set_config(&apConfig);		//设置 WiFi soft-AP 接口配置,并保存到 flash
}

void tcp_service_init()		//初始化
{
	WIFI_Init();  
	Inter213_InitTCP(8266);		//本地端口
}


TCP client(8266为TCP客户端,手机为TCP服务端)

提示:
ESP8266充当TCP客户端,必须要知道服务端的IP地址。所以我先在手机开启TCP服务端的时候,拿到手机的IP地址,之后把IP地址拷贝到代码里,写成死的!这时候才通讯。
代码的实现过程,定时器开启先连接至路由器,待成功连接路由器,则关闭定时器,开启TCP客户端连接。

TCP client流程分析 (即代码分析)

  1. 8266分区初始化

  2. 设置串口

  3. WiFi设置模式(station模式)

  4. esp8266 station初始化并使能

  5. 连接路由器

  6. 回调定时器函数Check_WifiState

    查询esp8266 station接口连接AP的状态
    设置目标(手机)IP地址
    查询 WiFi模块的 IP 地址
    连接到目标服务器的6000端口并回调my_station_init函数(分配空间,设置协议,设置本地端口,目标端口等,初始化TCP(相当于注册TCP连接) 成功就能(发送 接收 断开) 不成功就(打印错误代码 尝试重连) 最后启用连接)

代码


#include "driver/uart.h"  //串口0需要的头文件
#include "osapi.h"  //串口1需要的头文件
#include "user_interface.h" //WIFI连接需要的头文件
#include "espconn.h"//TCP连接需要的头文件
#include "mem.h" //系统操作需要的头文件
#include "gpio.h"

os_timer_t checkTimer_wifistate;
struct espconn user_tcp_conn;

void ICACHE_FLASH_ATTR user_tcp_sent_cb(void *arg)  //发送
{
	os_printf("发送数据成功!");
}
void ICACHE_FLASH_ATTR user_tcp_discon_cb(void *arg)  //断开
{
	os_printf("断开连接成功!");
}
void ICACHE_FLASH_ATTR user_tcp_recv_cb(void *arg,  //接收
		char *pdata, unsigned short len) {

	os_printf("收到数据:%s\r\n", pdata);
	espconn_sent((struct espconn *) arg, "0", strlen("0"));

}
void ICACHE_FLASH_ATTR user_tcp_recon_cb(void *arg, sint8 err) //注册 TCP 连接发生异常断开时的回调函数,可以在回调函数中进行重连
{
	os_printf("连接错误,错误代码为%d\r\n", err);
	espconn_connect((struct espconn *) arg);
}
void ICACHE_FLASH_ATTR user_tcp_connect_cb(void *arg)  //注册 TCP 连接成功建立后的回调函数
{
	struct espconn *pespconn = arg;
	espconn_regist_recvcb(pespconn, user_tcp_recv_cb);  //接收
	espconn_regist_sentcb(pespconn, user_tcp_sent_cb);  //发送
	espconn_regist_disconcb(pespconn, user_tcp_discon_cb);  //断开
	espconn_sent(pespconn, "8226", strlen("8226"));

}

void ICACHE_FLASH_ATTR my_station_init(struct ip_addr *remote_ip,
		struct ip_addr *local_ip, int remote_port)
 {
	user_tcp_conn.proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));  //分配空间
	user_tcp_conn.type = ESPCONN_TCP;  //设置类型为TCP协议
	os_memcpy(user_tcp_conn.proto.tcp->local_ip, local_ip, 4);
	os_memcpy(user_tcp_conn.proto.tcp->remote_ip, remote_ip, 4);
	user_tcp_conn.proto.tcp->local_port = espconn_port();  //本地端口
	user_tcp_conn.proto.tcp->remote_port = remote_port;  //目标端口
	//注册连接成功回调函数和重新连接回调函数
	espconn_regist_connectcb(&user_tcp_conn, user_tcp_connect_cb);//注册 TCP 连接成功建立后的回调函数
	espconn_regist_reconcb(&user_tcp_conn, user_tcp_recon_cb);//注册 TCP 连接发生异常断开时的回调函数,可以在回调函数中进行重连
	//启用连接
	espconn_connect(&user_tcp_conn);
}

void Check_WifiState(void) 
{
	uint8 getState;
	getState = wifi_station_get_connect_status();
	//查询 ESP8266 WiFi station 接口连接 AP 的状态
	if (getState == STATION_GOT_IP)
	 {
		os_printf("WIFI连接成功!\r\n");
		os_timer_disarm(&checkTimer_wifistate);
		struct ip_info info;
		const char remote_ip[4] = { 192, 168, 43, 1 };//目标IP地址,必须要先从手机获取,否则连接失败.
		wifi_get_ip_info(STATION_IF, &info);	//查询 WiFi模块的 IP 地址
		my_station_init((struct ip_addr *) remote_ip, &info.ip, 6000);//连接到目标服务器的6000端口
 }
}

void tcp_client_init()	//初始化
{

	wifi_set_opmode(0x01);	//设置为STATION模式

	struct station_config stationConf;
	os_strcpy(stationConf.ssid, "xiaofang");	  //改成你自己的   路由器的用户名
	os_strcpy(stationConf.password, "12345678"); //改成你自己的   路由器的密码
	wifi_station_set_config(&stationConf);	//设置WiFi station接口配置,并保存到 flash
	wifi_station_connect();	//连接路由器

	os_timer_disarm(&checkTimer_wifistate);	//取消定时器定时
	os_timer_setfn(&checkTimer_wifistate, (os_timer_func_t *) Check_WifiState,
	NULL);	//设置定时器回调函数
	os_timer_arm(&checkTimer_wifistate, 500, 1);	//启动定时器,单位:毫秒
}


猜你喜欢

转载自blog.csdn.net/qq_25205045/article/details/85379110