ESP8266开发之旅 网络篇⑩ UDP服务
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。
QQ技术互动交流群:ESP8266&32 物联网开发 群号622368884,不喜勿喷
一、你如果想学基于Arduino的ESP8266开发技术
一、基础篇
二、网络篇
- ESP8266开发之旅 网络篇① 认识一下Arduino Core For ESP8266
- ESP8266开发之旅 网络篇② ESP8266 工作模式与ESP8266WiFi库
- ESP8266开发之旅 网络篇③ Soft-AP——ESP8266WiFiAP库的使用
- ESP8266开发之旅 网络篇④ Station——ESP8266WiFiSTA库的使用
- ESP8266开发之旅 网络篇⑤ Scan WiFi——ESP8266WiFiScan库的使用
- ESP8266开发之旅 网络篇⑥ ESP8266WiFiGeneric——基础库
- ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
- ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
- ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
- ESP8266开发之旅 网络篇⑩ UDP服务
- ESP8266开发之旅 网络篇⑪ WebServer——ESP8266WebServer库的使用
- ESP8266开发之旅 网络篇⑫ 域名服务——ESP8266mDNS库
- ESP8266开发之旅 网络篇⑬ SPIFFS——ESP8266 Flash文件系统
- ESP8266开发之旅 网络篇⑭ web配网
- ESP8266开发之旅 网络篇⑮ 真正的域名服务——DNSServer
- ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新
三、应用篇
四、高级篇
1. 前言
前面的博文中,博主讲述的内容基本上都是Tcp以及Http通信的内容,那么我们当然得讲解一下Tcp的另外一个兄弟——UDP。
1.1 TCP与UDP优缺点
- TCP是面向连接,也就是发送数据之前是需要建立连接;UDP是面向无连接的,即发送数据之前不需要建立连接。
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力做到可靠,即不保证绝对可靠。
- UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
- TCP对系统资源要求较多,UDP对系统资源要求较少。
UDP 是 User Datagram Protocol 的简称,是一种无连接、不可靠的协议,每一个数据报都是一个独立的信息,它在网络上以任何可能的路径传到目的地,但不保证是否真的传到目的地、是否过程中真的保证了数据的完整性!
UDP就好像无手机时代,你要去探望亲戚,但是你不知道亲戚有没有在家(也就是说可能会丢包);
TCP就好像有手机时代,你要去探望亲戚,你会打电话过去提前沟通好,你会确保亲戚在家里才会买东西过去探望(数据不会丢包);
使用UDP服务,请在代码前加入一下头文件:
#include <WiFiUdp.h>
2. WiFiUDP库
老规矩,先上一个博主总结的百度脑图:

总体上,根据功能可以把方法分为4大类:
- 启动UDP服务方法;
- 处理发送过来的UDP包;
- 获取UDP client的信息;
- 发送UDP包;
2.1 启动UDP服务方法
2.1.1 begin —— 开启UDP服务
函数说明:
/**
* 初始化TCP服务,开始监听特定端口
* @return 1 表示成功
* 0 表示没有有效的socket可以用
*/
uint8_t begin(uint16_t port);
2.1.2 stop —— 停止UDP服务
函数说明:
/**
* 断开UDP连接
*/
void stop();
2.2 处理发送过来的UDP包
2.2.1 parsePacket —— 解析UDP数据包
函数说明:
/**
* 开始处理进来的UDP请求
* @return int 返回当前UDP包的大小,如果没有就返回0
*/
int parsePacket();
注意点:
- 此方法要在 available、read、peek之前调用(总结来说,就是读取数据之前应该解析数据);
2.2.2 available —— 判断UDP数据包可读大小
函数说明:
/**
* 返回当前udp包的可读剩余字节数据
*/
int available();
2.2.3 read —— 读取数据并清除
函数说明:
/**
* 读取当前udp数据包的一个字节,并从缓冲区清除该字节
* @return 单字节数据
*/
int read();
/**
* 读取当前udp数据包的len长度的数据,并从缓冲区清除该字节
* @param buffer 存储数据的内存空间
* @param len 需要读取的长度
* @return 读取成功字节数
*/
int read(unsigned char* buffer, size_t len);
注意点:
- 此方法读取完数据之后会把数据从缓冲区去掉;
2.2.4 peek —— 读取数据
函数说明:
/**
* 读取当前udp数据包的一个字节
* @return 单字节数据
*/
int peek();
注意点:
- 此方法读取完数据之后会不会把数据从缓冲区去掉;
- 建议尽量使用批量处理函数;
2.2.5 flush —— 清除缓冲区
函数说明:
/**
* 清除缓冲区
*/
void flush();
2.3 获取UDP 远端的信息
2.3.1 remoteIP —— 远端IP地址
函数说明:
/**
* 获取发送当前UDP包的主机IP地址
* @return IPAddress ip地址
*/
IPAddress remoteIP();
2.3.2 remotePort —— 远端端口
函数说明:
/**
* 获取发送当前UDP包的主机端口
* @return uint16_t 端口
*/
uint16_t remotePort();
2.4 发送UDP包
2.4.1 beginPacket —— 配置ip和port
函数说明:
/**
* 开始创建需要发送给远端主机的udp包
* @param ip 远端主机ip地址
* @param port 远端主机端口号
* @return 1 创建成功
* 0 创建失败
*/
int beginPacket(IPAddress ip, uint16_t port);
int beginPacket(const char *host, uint16_t port);
2.4.2 write —— 把数据写入发送缓冲区
函数说明:
/**
* 写入一字节数据到创建好的udp包
* @param uint8_t 单字节数据
* @return 1 写入成功
* 0 写入失败
*/
size_t write(uint8_t);
/**
* 写入字节数据到创建好的udp包
* @param buffer 字节数据缓冲区
* @return size_t 返回写入成功的字节数
*/
size_t write(const uint8_t *buffer);
/**
* 写入size字节数据到创建好的udp包
* @param buffer 字节数据缓冲区
* @param size 字节数据长度
* @return size_t 返回写入成功的字节数
*/
size_t write(const uint8_t *buffer, size_t size);
2.4.3 endPacket —— 发送数据
函数说明:
/**
* 把udp数据包发送出去
* @param uint8_t 单字节数据
* @return 1 发送成功
* 0 发送失败
*/
int endPacket();
3. 实例
3.1 通过UDP收发数据
实例说明
- ESP8266作为UDP服务端,把电脑UDP客户端发过来的数据打印到串口调试器,并回复应答信息;
源码:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "********";//wifi账号
const char* password = "********";//wifi密码
WiFiUDP Udp;
unsigned int localUdpPort = 4210; // 本地监听端口
char incomingPacket[255]; // 存储Udp客户端发过来的数据
char replyPacket[] = "Hi there! Got the message :-)"; // 应答信息
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");
//启动Udp监听服务
Udp.begin(localUdpPort);
//打印本地ip地址,udp client端会使用到
Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);
}
void loop()
{
//解析Udp数据包
int packetSize = Udp.parsePacket();
if (packetSize)
{
// 收到Udp数据包
Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
// 读取Udp数据包
int len = Udp.read(incomingPacket, 255);
if (len > 0)
{
incomingPacket[len] = 0;
}
//向串口调试器打印信息
Serial.printf("UDP packet contents: %s\n", incomingPacket);
//往udp 远端发送应答信息
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write(replyPacket);
Udp.endPacket();
}
}
注意点:
- 为了模拟UDP客户端请求,请下载使用以下软件 Packet Sender;
测试结果:
- ESP8266先开启UDP服务,然后Packet Sender发送UDP数据:


3.2 通过UDP控制LED
实例说明
- ESP8266作为UDP服务端,把电脑UDP客户端发过来的命令用来控制板载LED灯,其中 LED_ON 表示开灯,LED_OFF表示关灯,操作完毕后需要回复信息;
源码:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char *ssid = "********"; //wifi名称
const char *password = "********"; //wifi密码
WiFiUDP Udp;
unsigned int localUdpPort = 4210; // 本地端口号
char incomingPacket[255]; // 接收缓冲区
void setup()
{
//以下为基本功能初始化,初始化串口和网络和LED
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
Serial.println();
Serial.printf("Connecting to %s ", ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");
//以下开启UDP监听并打印输出信息
Udp.begin(localUdpPort);
Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);
}
void loop()
{
int packetSize = Udp.parsePacket(); //获取当前队首数据包长度
if (packetSize) // 有数据可用
{
Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
int len = Udp.read(incomingPacket, 255); // 读取数据到incomingPacket
if (len > 0) // 如果正确读取
{
incomingPacket[len] = 0; //末尾补0结束字符串
Serial.printf("UDP packet contents: %s\n", incomingPacket);
if (strcmp(incomingPacket, "LED_OFF") == 0) // 命令LED_OFF
{
digitalWrite(LED_BUILTIN, HIGH); // 熄灭LED
sendCallBack("LED has been turn off");
}
else if (strcmp(incomingPacket, "LED_ON") == 0) // 如果收到LED_ON
{
digitalWrite(LED_BUILTIN, LOW); // 点亮LED
sendCallBack("LED has been turn on");
}
else // 如果非指定消息
{
sendCallBack("Command Error!");
}
}
}
}
/**
* 发送响应信息
*/
void sendCallBack(const char *buffer){
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write(buffer); //回复内容
Udp.endPacket();
}
测试结果:
- ESP8266先开启UDP服务,然后Packet Sender发送UDP命令:


4. 总结
使用Arduino for esp8266可以非常简单实现UDP通讯过程。最重要需要记住的一点,那就是UDP面向无连接,发送出去的数据不会理会是否被收到。
ESP8266开发之旅 网络篇⑩ UDP服务的更多相关文章
- ESP8266开发之旅 网络篇⑯ 无线更新——OTA固件更新
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 网络篇⑦ TCP Server & TCP Client
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 网络篇⑧ SmartConfig——一键配网
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 网络篇⑨ HttpClient——ESP8266HTTPClient库的使用
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 网络篇⑪ WebServer——ESP8266WebServer库的使用
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 网络篇⑫ 域名服务——ESP8266mDNS库
1. 前言 前面的博文中,无论是作为client端还是server端,它们之间的通信都是通过具体的IP地址来寻址.通过IP地址来寻址,本身就是一个弊端,用户怎么会去记住这些魔法数字呢?那么有没 ...
- ESP8266开发之旅 网络篇⑬ SPIFFS——ESP8266 SPIFFS文件系统
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- ESP8266开发之旅 网络篇⑮ DNSServer——真正的域名服务
1. 前言 Arduino for esp8266中有两个DNS服务相关的库: ESP8266mDNS库 这个库是mDNS库,使用这个库的时候ESP8266可以在AP模式或是以STA模式接入局 ...
- ESP8266开发之旅 网络篇⑭ web配网
1. 前言 目前,市面上流行多种配网方式: WIFI模块的智能配网(SmartConfig以及微信AirKiss配网) SmartConfig 配网方式 请参考博主之前的博文 ESP8266开 ...
随机推荐
- Android嵌入式开发初学者的几个注意点
一:首先你必须了解ARM平台 Android 移植与驱动核心开发,当然也可以是X86和其他的平台,不过其他平台的Android智能终端开发并不是很多. Android嵌入式智能操作系统是基于Linux ...
- JNDI注入与反序列化学习总结
0x01.java RMI RMI(Remote Method Invocation)是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定 ...
- DOM之节点操作
DOM提供了很多实用的API,这些API让我们可以轻松的访问HTML文档.所谓API(应用程序接口),简单来说,就是让我们可以直接使用它访问程序的一些属性或方法,而不用了解程序内部的运作过程和原理. ...
- 最新2019Pycharm破解教程,附激活码!
本教程仅用作个人学习,请勿用于商业获利,造成后果自负!!! Pycharm安装 在这插一个小话题哈,Pycharm只是一个编译器,并不能代替Python,如果要使用Python,还是需要安装Pytho ...
- 【linux】【jenkins】自动化运维四 整合gitlab、docker发布java项目
jenkins发布java项目 过程参考发布vue项目.https://www.cnblogs.com/jxd283465/p/11543431.html 大同小异. vue建立的是Freestyle ...
- MYSQL增删改查添加外键
给商品表(从表)添加一个外键 ALTER TABLE product ADD CONSTRAINT FK_cno FOREIGN KEY(cno) REFERENCES category(cid 从 ...
- CAS详细登录流程(转)
转:https://www.cnblogs.com/lihuidu/p/6495247.html 4.CAS的详细登录流程 上图是3个登录场景,分别为:第一次访问www.qiandu.com.第二次访 ...
- volatile 关键字的作用
简介Java 语言提供了一种稍弱的同步机制,即 volatile 变量,用来确保将变量的更新操作通知到其他线程.volatile 变量具备两种特性:变量可见性.禁止重排序. 作为同步锁在访问 vola ...
- Java 多线程练习
题目:某公司组织年会,会议入场时有两个入口,在入场时每位员工都能获取一张双色球彩票,假设公司有100个员工,利用多线程模拟年会入场过程, 并分别统计每个入口入场的人数,以及每个员工拿到的彩票的号码.线 ...
- 初级Python
[toc] 一.数据类型 1.1基本数据类型 1.1.1数字类型 1.整数类型 十进制:1010,-219 二进制:以0b或0B开头:0b010,-0B101 八进制,以0o或0O开头:0o123,- ...