ESP32 MicroPython开发之旅 网络篇⑧ ——UDP通信,客户端与服务器

❤️博主介绍❤️
😬 作者:单片机菜鸟哥
👉火爆博客:ESP8266 Arduino教程

零基础从入门到熟悉Arduino平台下开发ESP8266,同时会涉及网络编程知识。专栏文章累计超过60篇,分为基础篇、网络篇、应用篇、高级篇,涵盖ESP8266大部分开发技巧。

👻最近更新:ESP32 MicroPython应用系列

讲解Python在esp32上的应用,包括网络请求、爬虫

❤️UDP通信,客户端与服务器❤️

前面的博文中,博主讲述的内容基本上都是Tcp以及Http通信的内容,那么我们当然得讲解一下Tcp的另外一个兄弟——UDP。

📢TCP与UDP优缺点

  1. TCP是面向连接,也就是发送数据之前是需要建立连接;UDP是面向无连接的,即发送数据之前不需要建立连接。
  • 首先 UDP 是不需要和 TCP一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分拼接操作。(也就是每个数据报之间是独立的,没有任何关联先后顺序,因此应用层数据必须选择合适大小的报文数据。)
  • 在网络数据传输模型中,发送端应用层将数据传递给传输层的 UDP,UDP 协议只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络IP层了
    在接收端,网络IP层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作
  1. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力做到可靠,即不保证绝对可靠

在这里插入图片描述

  • 首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。
    并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。
  • UDP 没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP,因为丢弃了一些数据无关紧要。
  1. UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
  • UDP头部开销小,传输数据报文时是很高效的
  1. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。

  2. TCP对系统资源要求较多,UDP对系统资源要求较少。

UDP 是 User Datagram Protocol 的简称,是一种无连接、不可靠的协议,每一个数据报都是一个独立的信息,它在网络上以任何可能的路径传到目的地,但不保证是否真的传到目的地、是否过程中真的保证了数据的完整性!

UDP就好像无手机时代,你要去探望亲戚,但是你不知道亲戚有没有在家(也就是说可能会丢包);

TCP就好像有手机时代,你要去探望亲戚,你会打电话过去提前沟通好,你会确保亲戚在家里才会买东西过去探望(数据不会丢包);

建议看这篇之前,可以先看看 ESP32 MicroPython开发之旅 网络篇④ ——TCP通信 核心思想需要理解。

在ESP32 MicroPython中,进行TCP/UDP通讯主要用到了usocket(套接字)模块。

  • MicroPython 提供丰富的网络功能,可以加快物联网应用的开发速度。了解网络功能之后,就可以将产品轻松的接入网络,实现更多物联网功能。
  • 在使用 MicroPython 进行网络编程首先需要了解的就是 usocket 模块,模块提供对BSD套接字接口的访问。

而在TCP/UDP基础上我们又会TCPClientTCPServerUDPClientUDPServer。TCP相关已经讲解,本篇重点讲解UDP相关。

目前基于UDP的应用层协议应用比较广泛就是CoAP

而在usocket 模块中,我们需要了解一些基本的常量(网络基础)含义:

  • IP地址类型

socket.AF_INET =2 — TCP/IP – IPv4
socket.AF_INET6 =10 — TCP/IP – IPv6

  • 套接字类型

socket.SOCK_STREAM =1 — TCP流(重点)
socket.SOCK_DGRAM =2 — UDP数据报(重点)
socket.SOCK_RAW =3 — 原始套接字
socket.SO_REUSEADDR =4 — socket可重用

  • IP协议号(在大多数情况下不需要指定这个,MicroPython也不推荐,作为了解即可)

socket.IPPROTO_TCP =16
socket.IPPROTO_UDP =17

  • 原因:因为 SOCK_STREAM 套接字类型会自动选择 IPPROTO_TCP 和 SOCK_DGRAM - IPPROTO_UDP。 因此,这些常量的唯一实际用途是作为 setsockopt() 的参数。

☀️UDPClient —— 客户端请求

在这里插入图片描述

这里博主特意用两种颜色区分STA和Client过程。

1.1 创建STA模式
import network
sta_if = network.WLAN(network.STA_IF)

注意:

  • 第一次按照MicroPython固件的时候,ESP32配置为热点模式,因此AP_IF接口有效,STA_IF接口无效。
1.2 激活station模式
import network
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
1.3 连接到您的WiFi网络
import network
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect('<your ESSID>', '<your password>')
1.4 检查连接是否建立
import network
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.isconnected()
1.5 创建socket对象
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
  • 使用给定的地址群、类型和协议号创建一个新的socket对象
1.6 构建ServerIP+ServerPort
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort
addr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
  • 将参数翻译为一个5元组序列,该序列包含创建一个与设备连接的socket所需的全部必要参数。
  • 该5元组列表有以下结构:

(family, sockettype, proto, canonname, sockaddr)
简称 ftpca

  • family: 表示socket使用的协议簇。常用的协议簇包括AF_UNIX(本机通信)/AF_INET(TCP/IP协议簇中的IPv4协议)/AF_INET6(TCP/IP协议簇中的IPv4协议)。在python的socket包中,用1表示AF_UNIX,2表示AF_INET,10表示AF_INET6。
  • sockettype:表示socket的类型。常见的socket类型包括SOCK_STREAM(TCP流)/SOCK_DGRAM(UDP数据报)/SOCK_RAW(原始套接字)。其中,SOCK_STREAM=1,SOCK_DGRAM=2,SOCK_RAW=3
  • proto:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP(=6)和IPPTOTO_UDP(=17),它们分别对应TCP传输协议、UDP传输协议。
  • canonname:主机名字
  • sockaddr:IP地址+端口

注意:

  • socket.getaddrinfo 返回的是一个元组数组(这里可以解释 [0][-1] 的由来,获取到IP地址和端口元组)。类似于:
[(2, 1, 6, '', ('220.181.111.86', 80)),
 (2, 2, 17, '', ('220.181.111.86', 80)),
 (2, 1, 6, '', ('123.125.114.144', 80)),
 (2, 2, 17, '', ('123.125.114.144', 80)),
 (2, 1, 6, '', ('220.181.111.85', 80)),
 (2, 2, 17, '', ('220.181.111.85', 80))]
  • 这个ftpca的 前三位可以用来构造一个socket。
2 是 AF_INET
1 是 SOCK_STREAM
6 是 IPPROTOTCP
1.7 发起请求
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort
addr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# 发起请求
print("esp32 micropython udp")
s.sendto("esp32 micropython udp",addr)
1.8 响应请求
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort
addr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# 发起请求
print("esp32 micropython udp")
s.sendto("esp32 micropython udp",addr)
# 响应请求
while True:
     data = s.recv(100)
     if data:
        print(str(data, 'utf8'), end='')
     else:
        break        
  • 从socket上接收数据。返回值是一个表示接收到的数据的字节对象。要接收到的数据最大数量由缓冲区大小指定。
1.9 关闭socket
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort
addr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# 发起请求
print("esp32 micropython udp")
s.sendto("esp32 micropython udp",addr)
# 响应请求
while True:
     data = s.recv(100)
     if data:
        print(str(data, 'utf8'), end='')
     else:
        break
# 关闭socket
s.close()                
  • 标记关闭的socket。一旦发生这种情况,所有将对socket对象进行的操作都将失败。远程端将无法再接收到任何数据(队列数据刷新后)。
  • Socket在垃圾回收时自动关闭,但是建议您明确地关闭它们

✨UDPClient 示例

本地局域网PC机构建UDPServer,ESP32访问它

步骤:

  • 网络调试助手打开UDPServer,获取本地主机IP地址和本地主机端口号port
  • esp32创建UDPClient,连接该IP和port,发送 “esp32 micropython udp”过去
  • 新建network_udp_client.py
# 导入usocket模块
import usocket
# 导入网络模块
import network

# 定义一个连接函数
def do_connect():
    # 创建STA模式
    sta_if = network.WLAN(network.STA_IF)
    # 返回网络工作状态
    print('network status1:', sta_if.status())
    # 检查连接是否建立
    if not sta_if.isconnected():
        print('connecting to network...')
        # 激活station模式
        sta_if.active(True)
        # 连接到您的WiFi网络
        sta_if.connect('TP-LINK_5344', 'xxxxxx')
        # 返回网络工作状态
        print('network status2:', sta_if.status())
        # 检查连接是否建立
        while not sta_if.isconnected():
            pass
    # 返回网络工作状态
    print('network status3:', sta_if.status())
    
# 开机自动连接
do_connect() 

# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort,这里得填写自己的网络调试助手
addr = usocket.getaddrinfo('192.168.1.105', 32666)[0][-1]
print(addr)
# 发起请求
print("esp32 micropython udp")
s.sendto("esp32 micropython udp",addr)
# 响应请求
while True:
     data = s.recv(100)
     if data:
        print(str(data, 'utf8'), end='')
     else:
        break
# 关闭socket
s.close()

  • 结果:
    在这里插入图片描述
>>> %Run -c $EDITOR_CONTENT
network status1: 1010
network status3: 1010
('192.168.1.105', 32666)
esp32 micropython udp

☀️UDPServer —— 服务端响应

在这里插入图片描述
这里博主特意用两种颜色区分STA和Server过程。

2.1 创建STA模式
import network
sta_if = network.WLAN(network.STA_IF)

注意:

  • 第一次按照MicroPython固件的时候,ESP32配置为热点模式,因此AP_IF接口有效,STA_IF接口无效。
2.2 激活station模式
import network
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
2.3 连接到您的WiFi网络
import network
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect('<your ESSID>', '<your password>')
2.4 检查连接是否建立
import network
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.isconnected()
2.5 创建socket对象
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
  • 使用给定的地址群、类型和协议号创建一个新的socket对象
2.6 构建ServerIP+ServerPort
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort
addr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
  • 将参数翻译为一个5元组序列,该序列包含创建一个与设备连接的socket所需的全部必要参数。
  • 该5元组列表有以下结构:

(family, sockettype, proto, canonname, sockaddr)
简称 ftpca

  • family: 表示socket使用的协议簇。常用的协议簇包括AF_UNIX(本机通信)/AF_INET(TCP/IP协议簇中的IPv4协议)/AF_INET6(TCP/IP协议簇中的IPv4协议)。在python的socket包中,用1表示AF_UNIX,2表示AF_INET,10表示AF_INET6。
  • sockettype:表示socket的类型。常见的socket类型包括SOCK_STREAM(TCP流)/SOCK_DGRAM(UDP数据报)/SOCK_RAW(原始套接字)。其中,SOCK_STREAM=1,SOCK_DGRAM=2,SOCK_RAW=3
  • proto:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP(=6)和IPPTOTO_UDP(=17),它们分别对应TCP传输协议、UDP传输协议。
  • canonname:主机名字
  • sockaddr:IP地址+端口

注意:

  • socket.getaddrinfo 返回的是一个元组数组(这里可以解释 [0][-1] 的由来,获取到IP地址和端口元组)。类似于:
[(2, 1, 6, '', ('220.181.111.86', 80)),
 (2, 2, 17, '', ('220.181.111.86', 80)),
 (2, 1, 6, '', ('123.125.114.144', 80)),
 (2, 2, 17, '', ('123.125.114.144', 80)),
 (2, 1, 6, '', ('220.181.111.85', 80)),
 (2, 2, 17, '', ('220.181.111.85', 80))]
  • 这个ftpca的 前三位可以用来构造一个socket。
2 是 AF_INET
1 是 SOCK_STREAM
6 是 IPPROTOTCP
2.7 绑定地址
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort
addr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# 绑定地址
s.bind(addr)
  • 将套接字绑定到地址,套接字不能是已经绑定的。
2.8 响应请求
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort
addr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# 绑定地址
s.bind(addr
# 响应请求
while True:
     data = s.recv(100)
     if data:
        print(str(data, 'utf8'), end='')
     else:
        break        
  • 从socket上接收数据。返回值是一个表示接收到的数据的字节对象。要接收到的数据最大数量由缓冲区大小指定。
2.9 关闭socket
# 导入usocket模块
import usocket
# 创建 udp socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort
addr = socket.getaddrinfo('www.micropython.org', 80)[0][-1]
# 发起请求
print("esp32 micropython udp")
s.sendto("esp32 micropython udp",addr)
# 响应请求
while True:
     data = s.recv(100)
     if data:
        print(str(data, 'utf8'), end='')
     else:
        break
# 关闭socket
s.close()                
  • 标记关闭的socket。一旦发生这种情况,所有将对socket对象进行的操作都将失败。远程端将无法再接收到任何数据(队列数据刷新后)。
  • Socket在垃圾回收时自动关闭,但是建议您明确地关闭它们

✨UDPServer 示例

本地局域网PC机构建UDPClient,访问ESP32 UDPServer

步骤:

  • 网络调试助手打开UDPClient,获取本地主机IP地址和本地主机端口号port
  • esp32创建UDPServer,处理发过来的数据
  • 新建network_udp_server.py
# 导入usocket模块
import usocket
# 导入网络模块
import network

# 定义一个连接函数
def do_connect():
    # 创建STA模式
    sta_if = network.WLAN(network.STA_IF)
    # 返回网络工作状态
    print('network status1:', sta_if.status())
    # 检查连接是否建立
    if not sta_if.isconnected():
        print('connecting to network...')
        # 激活station模式
        sta_if.active(True)
        # 连接到您的WiFi网络
        sta_if.connect('TP-LINK_5344', 'xxxxxxxx')
        # 返回网络工作状态
        print('network status2:', sta_if.status())
        # 检查连接是否建立
        while not sta_if.isconnected():
            pass
    # 返回网络工作状态
    print('network :', sta_if.ifconfig())
    
# 开机自动连接
do_connect() 

# 创建 UDP socket
s = usocket.socket(usocket.AF_INET,usocket.SOCK_DGRAM)  
# 构建ServerIP+ServerPort,这里得填写自己的网络调试助手
addr = usocket.getaddrinfo('192.168.1.102', 32666)[0][-1]
print(addr)
# 绑定地址
s.bind(addr)
# 响应请求
while True:
     data,clientaddr = s.recvfrom(1024)
     print("data:",data)
     print("from:",clientaddr)
     if data:
        print(str(data, 'utf8'), end='')
     else:
        break
# 关闭socket
s.close()

结果:
在这里插入图片描述

>>> %Run -c $EDITOR_CONTENT
network status1: 1010
network : ('192.168.1.102', '255.255.255.0', '192.168.1.1', '192.168.1.1')
('192.168.1.102', 32666)
data: b'from Packet Sender'
from: ('192.168.1.105', 64657)
from Packet Senderdata: b'from Packet Sender'
from: ('192.168.1.105', 64657)
from Packet Sender
  • 4
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,我知道了。针对你的问题,我能够为你提供如下的解答: 在使用 MicroPython 和 ESP8266 控制 LED 的过程中,可以通过 PWM 技术实现呼吸灯效果。PWM(Pulse Width Modulation)脉宽调制技术是一种通过改变信号的占空比来控制电路输出功率的技术。 具体实现步骤如下: 1. 首先需要在 ESP8266 上安装 MicroPython,然后连接 ESP8266 和 LED。 2. 在 MicroPython 中,可以使用 machine 模块中的 Pin 和 PWM 类来控制 LED。 3. 先使用 Pin 类将 LED 连接到 ESP8266 上的一个 GPIO 引脚。 4. 再使用 PWM 类来初始化一个 PWM 对象,并设置 PWM 对象的频率和占空比。 5. 最后使用 PWM 对象的 duty() 方法来改变占空比,从而控制 LED 显示的亮度。 下面是一个简单的 MicroPython 代码示例,用于控制 LED 呼吸灯效果: ```python from machine import Pin, PWM import time led_pin = Pin(2, Pin.OUT) # 连接到GPIO2 pwm = PWM(led_pin, freq=5000) # 初始化PWM对象,设置频率为5000Hz while True: for duty_cycle in range(0, 1024, 8): # 从0到1024,每次增加8 pwm.duty(duty_cycle) # 设置占空比 time.sleep_ms(5) # 暂停5ms for duty_cycle in range(1023, -1, -8): # 从1023到0,每次减少8 pwm.duty(duty_cycle) # 设置占空比 time.sleep_ms(5) # 暂停5ms ``` 上面的代码中,使用了一个无限循环来让 LED 一直显示呼吸灯效果。在每个循环中,通过循环改变占空比,从而让 LED 呈现出呼吸灯效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

单片机菜鸟爱学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值