[网络篇]ESP8266-SDK教程(三)之TCP通信Server<->Client

纳尼?昨天刚刚打印了个“Hello World!”,今天你就让我学习TCP通信?有没有搞错~哈哈,相信很多读者会很迷,其实学习这东西嘛,单单学一些比较简单的,相信没两天就没人看了,所以咱就在基础篇和网络篇穿插着去学习一下ESP8266,毕竟兴趣才是最好的老师嘛!大家以后遇到问题了,来翻文章建议大家根据[XX篇]去快速定位该去哪一篇文章中去查找问题,当然具体会在哪一篇文章中有讲,也不一定了,后面也会穿插着写一点[项目篇][进阶篇][闲扯篇],总的来说就是,本系列文章并没有固定的路线,大家不如忍忍?当然这里写的文章也不一定是对的,大家在实际测试中如果遇到了问题,还请私信我,或者在Github上提交issue!

闲话少说,既然要学习TCP通信的知识,那么我们得先要了解一下TCP到底是个什么东西(玩意),正所谓孙子曾经曰过“知彼知己,百战不殆”,那我们先补一些关于TCP的知识吧!

TCP基础知识:

  • 是什么?

TCP(Transmission Control Protocol传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。(百度词条搜到的~)

说白了就是一种传输协议,就像我们串口、232、485等一样的通讯协议,只不过TCP多用于网络间的通讯,不过TCP是在IP层之上的,相信你肯定见过或者听说过TCP/IP协议,没错,这哥俩是绑在一块的,TCP是依赖IP协议的。

  • 通讯机制

TCP与我们常使用的串口等通讯协议有什么不同呢?首先是两台主机建立TCP连接机制是比较麻烦的,要经过三次握手协议,才能建立连接,过程用汉字描述如下:

    • 客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。
    • 服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。
    • 客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。

看字比较麻烦,我们还是看图吧!

既然有建立连接,那么肯定也有断开连接,但是没想到断开连接比建立连接还要麻烦,还有四次挥手协议,纳尼?是的,断开连接需要经过四次挥手协议,直接看图吧:

  • 可靠性

上面说的通讯机制之所以这么麻烦,主要还是为了传输的可靠性,因为TCP是在整个网络中去传输,只要你有IP地址,并且在广域网中访问,那我们就可以建立TCP连接,说会悄悄话~所以,两者之间的可靠性就显得很重要了,客户端与服务端之间的连接可靠性靠很多策略去实现的比如心跳包机制,这里就不再详细叙述了,有点跑题了,这是ESP8266学习笔记~

  • 数据包格式

TCP的数据包相对来说是比较麻烦的,确认信息占据了整个数据包的很大一部分,设计的这么复杂主要原因还是保证在整个网络当中每包数据传输的正确性,这里我们就看一下数据包到底有多么复杂:

  • ESP8266作为TCP Client跟Server(PC)通信

了解了一点点基础知识后,我们还是要落实到实践上,下面我们正式开始,首先我们需要先看一下官方SDK编程指导手册,还没有?不知道去哪里下?好嘞,直接戳下面卡片下载好了~

官方SDK编程指导手册

英文版戳这里,如果你英语跟小编一样好的话,建议看英文版,要不断提升自己的英语~

官方SDK编程指导手册英文版

咳咳咳,那我们先打开这个英文文档,找到97页的TCP/UDP接口,我们先看一下接口分了几类:

咳咳咳,不要怀疑,使用的PDF查看软件有自动翻译动能,手动滑稽.jpg,可以看到一共分了4类,本篇文章我们先研究下通用 API和TCP API,关于UDP和mDNS的我们再后面的文章中再继续学习,你可以先大体看一下,每个API的注释都讲的很明白,我们不妨直接copy点代码直接跑一下?

1 git clone [email protected]:imliubo/makingfunxyz-esp8266.git 2 3 #如果之前有clong过,可以直接 git pull,不会用?那肯定是没好好看廖雪峰的git教程

下载完成后,打开ESP_IDE导入在makingfunxyz-esp8266-NONOS文件中的6.TCP_UDP_Server_Client这个工程,然后先修改一点东西,这一步很重要,请不要忽略:

Wi-Fi名称跟密码相信你肯定知道,TCP_SERVER_IP应该要修改成什么呢?就是你电脑的IP地址,这里每个人的都不一样,建议你先去查看一下,方法看视频~

视频还在找托管方~

可以看到我这里是192.168.0.109,那我就将它修改成192.168.0.109,这三个地方都修改好了后,我们直接先编译代码,先跑一下看看!编译好代码后,下载到ESP8266,这里跟上篇文章中是一样的,就不再详述,下载地址参考:

  • eagle.flash.bin-------->0x00000
  • eagle.irom0text.bin---->0x10000
  • esp_init_data_default_v08.bin --> 0x3FC000
  • blank.bin --> 0x3FE000

下载完成后,我们先不要急着去看结果,因为我们还没有开启TCP Server,那我们该怎么开启TCP Server呢?我这里用Python写了一个很简单的Server端程序,大家可以使用我这个,要是使用别的TCP调试助手,注意TCP_SERVER_PORT也要修改一下,运行我们的Server很简单,但是你需要安装一下Python,我这里没有打包成可执行文件,先去安装一下Python吧,我用的是Python3,建议大家也安装Python3,因为Python2跟Python3有些语法不一样,戳卡片下载:

Python下载安装

下载安装完成后,开始搞起来,我们需要在6.TCP_UDP_Server_Client这个文件夹下找到TCP_Server.py这个文件夹,然后打开修改一下IP地址,将IP地址修改成上面我们查看的本机地址,看图:

最后我们还需要设置一下开放端口,这里步骤有点多,就不再细述了,大家可以直接看这个百度知道,写的很详细:

百度知道开放端口

然后打开命令窗口,具体操作办法,在此文件下按住shift键,然后右键选择打开powershell窗口(WIN7 应该是cmd窗口),然后:

1 start cmd 2 #可以直接在powershell里面执行,但是我还是比较喜欢cmd窗口,所以就~win7不用,因为打开的就是cmd窗口 3 #cmd窗口打开后,输入以下命令 4 python TCP_Server.py

视频还在找托管方~

  • ESP8266作为TCP Server跟Client(PC)通信

上面是ESP8266作为Client去跟Server通信,但是ESP8266不仅可以作为Client还可以作为Server等待Client去建立连接去通信,这里我们修改几个地方,就可以将ESP8266作为Server去跟Client通信了,我在源码中已经都写好了,这里我们将同样将ESP8266的6666作为PC去连接的端口号:

其中TCP_Client.py文件中的IP地址需要在ESP8266上电打印后修改一下,我们将上面小节中的tcp_client_init()注释掉,tcp_server_init()取消注释,然后重新编译代码下载就好了,PC上的Client程序跟Server程序运行一样,这里我们直接看一下视频吧!

视频还在找托管方~

这里代码就不再解释了,我写的注释还算全,大家一看就懂,主要代码:

  1 /****************************
  2  *   TCP CLIENT FUNCTIONS   *
  3  ****************************/
  4
  5 /**********************************
  6  *  TCP CLIENT STATIC PROTOTYPES  *
  7  **********************************/
  8 static void tcp_client_sent_cb(void *arg);
  9 static void tcp_client_recv_cb(void *arg,char *pdata,unsigned short length);
 10 static void tcp_client_recon_cb(void *arg,sint8 error);
 11 static void tcp_client_discon_cb(void *arg);
 12 static void tcp_client_connect_cb(void *arg);
 13
 14 /**********************************
 15  *   TCP CLIENT STATIC VARIABLES  *
 16  **********************************/
 17 os_timer_t tcp_client_send_data_timer;
 18 struct espconn tcp_client;
 19 uint8 i;
 20
 21 /**********************************
 22  *   TCP CLIENT STATIC FUNCTIONS  *
 23  **********************************/
 24
 25 /**
 26  * TCP Client数据发送回调函数
 27  */
 28 static void ICACHE_FLASH_ATTR
 29 tcp_client_sent_cb(void *arg){
 30     os_printf("tcp client send data successful\r\n");
 31 }
 32
 33 /**
 34  * TCP Client数据接收回调函数,可以在这处理收到Server发来的数据
 35  */
 36 static void ICACHE_FLASH_ATTR
 37 tcp_client_recv_cb(void *arg,char *pdata,unsigned short len){
 38     os_printf("tcp client receive tcp server data\r\n");
 39     os_printf("length: %d \r\ndata: %s\r\n",len,pdata);
 40
 41     //TO DO
 42
 43     /**
 44      *process the receive data
 45      */
 46 }
 47
 48 /**
 49  * TCP Client重连回调函数,可以在此函数里做重连接处理
 50  */
 51 static void ICACHE_FLASH_ATTR
 52 tcp_client_recon_cb(void *arg,sint8 error){
 53     os_printf("tcp client connect tcp server error %d\r\n",error);
 54     os_timer_disarm(&tcp_client_send_data_timer);//取消定时发送数据定时器
 55 }
 56
 57 /**
 58  * TCP Client断开连接回调函数
 59  */
 60 static void ICACHE_FLASH_ATTR
 61 tcp_client_discon_cb(void *arg){
 62     os_printf("tcp client disconnect tcp server successful\r\n");
 63     os_timer_disarm(&tcp_client_send_data_timer);
 64 }
 65
 66 /**
 67  * TCP Client连接成功回调函数
 68  */
 69 static void ICACHE_FLASH_ATTR
 70 tcp_client_connect_cb(void *arg){
 71     struct espconn *pespconn = arg;
 72
 73     os_printf("tcp client connect tcp server successful\r\n");
 74     espconn_regist_recvcb(pespconn,tcp_client_recv_cb);//注册接收数据回调函数
 75     espconn_regist_sentcb(pespconn,tcp_client_sent_cb);//注册数据发送完成回调函数
 76     espconn_regist_disconcb(pespconn,tcp_client_discon_cb);//注册断开连接回调函数
 77
 78     os_timer_disarm(&tcp_client_send_data_timer);
 79     os_timer_setfn(&tcp_client_send_data_timer, (os_timer_func_t *) tcp_client_send_data,NULL);//注册Client定时发送数据回调函数
 80     os_timer_arm(&tcp_client_send_data_timer, 1000, true);//时间设置为1s
 81 }
 82
 83 /**********************************
 84  *   TCP CLIENT GLOBAL FUNCTIONS  *
 85  **********************************/
 86 /**
 87  * TCP Client定时发送数据回调函数
 88  */
 89 void ICACHE_FLASH_ATTR
 90 tcp_client_send_data(void){
 91     char buf[256],length;
 92     os_printf("tcp client send data tcp server\r\n");
 93     length = os_sprintf(buf,(char *)"Hi this is ESP8266 client! message num %d",i);
 94     i++;
 95     espconn_sent(&tcp_client,buf,length);
 96 }
 97
 98 /**
 99  * TCP Client初始化函数
100  * @remote_ip    要连接的TCP Server IP地址
101  * @local_ip     ESP8266 IP地址
102  * @remote_port  要连接的TCP Server端口号
103  */
104 void ICACHE_FLASH_ATTR
105 tcp_client_init(uint8 *remote_ip,struct ip_addr *local_ip, int remote_port){
106
107     uint32 server_ip = ipaddr_addr(remote_ip);
108
109     os_printf("tcp client connect to tcp server\r\n");
110     tcp_client.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
111     tcp_client.type = ESPCONN_TCP;
112
113     os_memcpy(tcp_client.proto.tcp->remote_ip,&server_ip,4);//设置要连接的Server IP地址
114     tcp_client.proto.tcp->remote_port = remote_port;//设置要连接的Server 端口号
115     os_memcpy(tcp_client.proto.tcp->local_ip,local_ip,4);//设置本地IP地址
116     tcp_client.proto.tcp->local_port = espconn_port();//设置本地端口号
117
118     espconn_regist_connectcb(&tcp_client,tcp_client_connect_cb);//注册连接成功回调函数
119     espconn_regist_reconcb(&tcp_client,tcp_client_recon_cb);//注册断连重新连接回调函数
120
121     espconn_connect(&tcp_client);//Client连接Server
122 }
123
124
125
126 /****************************
127  *   TCP SERVER FUNCTIONS   *
128  ****************************/
129 /**********************************
130  *  TCP SERVER STATIC PROTOTYPES  *
131  **********************************/
132 static void tcp_server_sent_cb(void *arg);
133 static void tcp_server_recv_cb(void *arg,char *pdata,unsigned short length);
134 static void tcp_server_recon_cb(void *arg,sint8 error);
135 static void tcp_server_discon_cb(void *arg);
136 static void tcp_server_listen_cb(void *arg);
137
138 /**********************************
139  *   TCP SERVER STATIC VARIABLES  *
140  **********************************/
141 os_timer_t tcp_server_send_data_timer;
142 struct espconn tcp_server;
143 uint8 z;
144
145 /**********************************
146  *   TCP server STATIC FUNCTIONS  *
147  **********************************/
148
149 /**
150  * TCP Server数据发送回调函数
151  */
152 static void ICACHE_FLASH_ATTR
153 tcp_server_sent_cb(void *arg){
154     os_printf("tcp server send data successful\r\n");
155
156 }
157
158 /**
159  * TCP Server数据接收回调函数,可以在这处理收到Client发来的数据
160  */
161 static void ICACHE_FLASH_ATTR
162 tcp_server_recv_cb(void *arg,char *pdata,unsigned short len){
163     os_printf("tcp server receive tcp client data\r\n");
164     os_printf("length: %d \r\ndata: %s\r\n",len,pdata);
165
166     //TO DO
167
168     /**
169      *process the receive data
170      */
171 }
172
173 /**
174  * TCP Server重连回调函数,可以在此函数里做重连接处理
175  */
176 static void ICACHE_FLASH_ATTR
177 tcp_server_recon_cb(void *arg,sint8 error){
178     os_printf("tcp server connect tcp client error %d\r\n",error);
179     os_timer_disarm(&tcp_server_send_data_timer);
180 }
181
182 /**
183  * TCP Server断开连接回调函数
184  */
185 static void ICACHE_FLASH_ATTR
186 tcp_server_discon_cb(void *arg){
187     os_printf("tcp server disconnect tcp client successful\r\n");
188     os_timer_disarm(&tcp_server_send_data_timer);
189 }
190
191 /**
192  * TCP Server监听Client连接回调函数
193  */
194 static void ICACHE_FLASH_ATTR
195 tcp_server_listen_cb(void *arg){
196     struct espconn *pespconn = arg;
197
198     os_printf("tcp server have tcp client connect\r\n");
199     espconn_regist_recvcb(pespconn,tcp_server_recv_cb);//注册收到数据回调函数
200     espconn_regist_sentcb(pespconn,tcp_server_sent_cb);//注册发送完数据回调函数
201     espconn_regist_disconcb(pespconn,tcp_server_discon_cb);//注册断开连接回调函数
202
203     os_timer_disarm(&tcp_server_send_data_timer);
204     os_timer_setfn(&tcp_server_send_data_timer, (os_timer_func_t *) tcp_server_send_data,NULL);//注册Server定时发送数据回调函数
205     os_timer_arm(&tcp_server_send_data_timer, 1000, true);//设置时间为1s
206 }
207
208 /**********************************
209  *   TCP CLIENT GLOBAL FUNCTIONS  *
210  **********************************/
211
212 /**
213  * TCP Server定时发送数据回调函数
214  */
215 void ICACHE_FLASH_ATTR
216 tcp_server_send_data(void){
217     char buf[256],length;
218     os_printf("tcp server send data tcp client\r\n");
219     length = os_sprintf(buf,(char *)"Hi this is ESP8266 server! message num %d",z);
220     z++;
221     espconn_send(&tcp_server,buf,length);
222 }
223
224 /**
225  * TCP Server初始化函数
226  * @local_port 本地监听端口号,与Client连接的端口号一致
227  */
228 void ICACHE_FLASH_ATTR
229 tcp_server_init(uint16 local_port){
230
231     os_printf("tcp server waiting tcp client connect!\r\n");
232     tcp_server.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
233     tcp_server.type = ESPCONN_TCP;
234
235     tcp_server.proto.tcp->local_port = local_port;//设置本地监听的端口号,等待Client连接
236
237     espconn_regist_connectcb(&tcp_server,tcp_server_listen_cb);//注册Server监听回调函数
238     espconn_regist_reconcb(&tcp_server,tcp_server_recon_cb);//注册断连重新连接回调函数
239
240     espconn_accept(&tcp_server);//创建Server,开始监听
241     espconn_regist_time(&tcp_server,360,0);//超时断开连接时间
242 }

user_main.c中的主要代码:

 1 os_timer_t wifistate_checktimer;
 2 void ICACHE_FLASH_ATTR
 3 WifiStatus_Check(void){
 4     uint8 wifiStatus;
 5     wifiStatus = wifi_station_get_connect_status();
 6     if (wifiStatus == STATION_GOT_IP) {
 7         os_printf("WiFi connection is successful!\r\n");
 8         os_timer_disarm(&wifistate_checktimer);
 9         struct ip_info local_ip;
10         wifi_get_ip_info(STATION_IF,&local_ip);
11         tcp_client_init(TCP_SERVER_IP,&local_ip.ip,TCP_SERVER_PORT);//TCP Client初始化,Client与Server只能二选一
12 //        tcp_server_init(TCP_LOCAL_PORT);//TCP Server初始化,Client与Server只能二选一
13     }else{
14         os_printf("WiFi connection failed!\r\n");
15     }
16 }
17
18 /**
19  * Wi-Fi连接回调函数
20  */
21 void ICACHE_FLASH_ATTR
22 wifiConnectCb(uint8_t status){
23
24     os_timer_disarm(&wifistate_checktimer);
25     os_timer_setfn(&wifistate_checktimer, (os_timer_func_t *) WifiStatus_Check,NULL);
26     os_timer_arm(&wifistate_checktimer, 2000, true);
27 }
28
29 void ICACHE_FLASH_ATTR
30 user_init(void)
31 {
32     os_printf("\nHello World! ZHIHU IAMLIUBO\n\n");
33
34     wifi_set_opmode(0x01);
35
36     WIFI_Connect(STA_SSID, STA_PASS, wifiConnectCb);//
37 }

最后附上我的ESP8266仓库,后面代码会全部在此仓库更新,欢迎小伙伴们Star~

makingfunxyz-esp8266

本系列文章在知乎同步更新,知乎搜索专栏:IAMLIUBO的神奇物联网之旅

原文地址:https://www.cnblogs.com/imliubo/p/10090857.html

时间: 2024-11-07 03:26:57

[网络篇]ESP8266-SDK教程(三)之TCP通信Server<->Client的相关文章

第三篇——第二部分——第三文 配置SQL Server镜像——域环境

原文:第三篇--第二部分--第三文 配置SQL Server镜像--域环境 原文出处:http://blog.csdn.net/dba_huangzj/article/details/28904503 本文将演示如何在域环境下部署镜像,在域中部署相对来说简单很多,但是很多企业并不真正使用域来管理服务器(本人所在的公司就是其一),所以有必要演示非域环境,并且重点放在非域环境下.但是作为实践经验和最佳建议,强烈使用域环境管理.非域环境将在第四文中演示:http://blog.csdn.net/dba

WIFI模块开发教程之W600网络篇2:AP模式下TCP Server通信

前言 本文研究如何在AP模式下进行TCP Server通信,所谓AP模式是说模块起来一个softAP热点,可以供其他WIFI设备连接,当其他设备连接成功后,另WIFI模块作为服务端,等待局域网中其他客户端连接后通信. 一. 理论基础 本节要处理的有两个问题,其一是如何利用RT_Thread连接路由器,其二是如何使用Socket套接字编程搞定TCP Server程序编写. 1.连接路由器 模块需要开启station,并且连接到一个路由器,RT_Thread中只需要调用wlan.mgnt.h中的函数

WIFI模块开发教程之W600网络篇1:AP模式下TCP Client通信

前言 本文研究如何在AP模式下进行TCP Client通信,所谓AP模式是说模块起来一个softAP热点,可以供其他WIFI设备连接,当其他设备连接成功后,另WIFI模块作为客户端,局域网中其他设备作为服务端进行TCP数据通信. 一.理论基础 本节要处理的有两个问题,其一是如何利用RT_Thread起来一个softAP,其二是如何使用Socket套接字编程搞定TCP Client程序编写. 1.模块开启SoftAP 模块需要起来一个名字为sand,密码为12345678的热点,RT_Thread

c tcp sockt server client -- demo

server.c // // Created by gxf on 2020/2/6. // #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> #define BUFFSIZE 1024 void dealClientConnecti

第三篇——第二部分——第五文 配置SQL Server镜像——域环境SQL Server镜像日常维护

本文接上面两篇搭建镜像的文章: 第三篇--第二部分--第三文 配置SQL Server镜像--域环境:http://blog.csdn.net/dba_huangzj/article/details/28904503第三篇--第二部分--第四文 配置SQL Server镜像--非域环境:http://blog.csdn.net/dba_huangzj/article/details/27652857 在搭建的过程中,可能你会遇到比较多的问题,下面介绍一些常见的问题及解决方案,另外把主要精力放到对

Java网络编程之TCP通信

一.概述 Socket类是Java运行clientTCP操作的基础类,这个类本身使用代码通过主机操作系统的本地TCP栈进行通信. Socket类的方法会建立和销毁连接,设置各种Socket选项. ServerSocket类是Java执行server端操作的基础类,该类执行于server,监听入站TCP连接.每一个socketserver监听server的某个port.当远程主机的client尝试连接此port时.server就被唤醒.并返回一个表示两台主机之间socket的正常Socket对象.

【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验三:按键模块② — 点击与长点击

实验三:按键模块② - 点击与长点击 实验二我们学过按键功能模块的基础内容,其中我们知道按键功能模块有如下操作: l 电平变化检测: l 过滤抖动: l 产生有效按键. 实验三我们也会z执行同样的事情,不过却是产生不一样的有效按键: l 按下有效(点击): l 长按下有效(长点击). 图3.1 按下有效,时序示意图. 图3.2 长按下有效,时序示意图. 如图3.1所示,按下有效既是"点击",当按键被按下并且消抖完毕以后,isSClick信号就有被拉高一个时钟(Short Click).

iOS开发网络篇—文件下载(三&#183;进度条)

一.实现下载文件进度控制 1.代码示例 1 #import "YYViewController.h" 2 3 @interface YYViewController () 4 @property(nonatomic,strong)NSMutableData *fileData; 5 @property(nonatomic,strong)NSFileHandle *writeHandle; 6 @property(nonatomic,assign)long long currentLen

ESP8266开发之旅 网络篇? SPIFFS——ESP8266 SPIFFS文件系统

1. 前言 ????在前面博文关于ESP8266WiFiWebServer的例程中,大家可以发现,博主基本上都是手动拼装html内容返回,html的内容被固定写在我们的Arduino ESP代码中. ????那么这样就有两点弊端: ESP8266代码相当臃肿 为了开发方便,web server网页除了自身的html内容之外,还包括一些css文件,甚至引入了JQuery库以及一些图片相关资源.如果把这些内容也直接写入到ESP8266代码中,会导致8266整体代码变大,甚至可能超过flash规定的大