文章目录

  • ❤️UDP通信,客户端与服务器❤️
  • 📢TCP与UDP优缺点
  • ☀️UDPClient —— 客户端请求
  • 1.1 创建STA模式
  • 1.2 激活station模式
  • 1.3 连接到您的WiFi网络
  • 1.4 检查连接是否建立
  • 1.5 创建socket对象
  • 1.6 构建ServerIP+ServerPort
  • 1.7 发起请求
  • 1.8 响应请求
  • 1.9 关闭socket
  • ✨UDPClient 示例
  • 本地局域网PC机构建UDPServer,ESP32访问它
  • ☀️UDPServer —— 服务端响应
  • 2.1 创建STA模式
  • 2.2 激活station模式
  • 2.3 连接到您的WiFi网络
  • 2.4 检查连接是否建立
  • 2.5 创建socket对象
  • 2.6 构建ServerIP+ServerPort
  • 2.7 绑定地址
  • 2.8 响应请求
  • 2.9 关闭socket
  • ✨UDPServer 示例
  • 本地局域网PC机构建UDPClient,访问ESP32 UDPServer


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

📢TCP与UDP优缺点

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

esp32 ble 发送数据 uuid esp32 udp_UDP

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

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

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

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


  • 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 —— 客户端请求

esp32 ble 发送数据 uuid esp32 udp_网络_02

这里博主特意用两种颜色区分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 —— 服务端响应

esp32 ble 发送数据 uuid esp32 udp_UDP_03


这里博主特意用两种颜色区分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()

结果:

esp32 ble 发送数据 uuid esp32 udp_服务器_04

>>> %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