【Pico 以太网实战系列 4/6】UDP 协议实操:MicroPython 实现回显服务器

UDP 协议实验

UDP 是一种无连接的传输层协议,适用于需要快速、简单数据传输而无需建立和维护连接的应用,它不需要预先建立连接就可以发送数据。每个数据报独立发送,不需要建立和维持连接状态。

使用 UDP 协议进行通信的工作流程如下:

  1. 创建 UDP​​套接字 :每个设备(主机)首先需要创建一个 UDP 套接字;
  2. 绑定到端口 :每个 UDP 套接字都会绑定到一个特定的端口号,这个端口号就像是主机上的一个特定的门牌号,使得外部的数据包能够找到正确的应用程序;
  3. 发送数据 :当主机需要发送数据时,它会将数据传递给 UDP 协议,UDP 协议会在数据前面添加一个 UDP 头,然后将数据(现在称为"**数据报**")发送到网络;
  4. 接收数据:在接收端,数据报被路由到正确的主机和端口,然后传递给相应的应用程序。

以下代码可以在我们提供的资料包中 elegance-devkit v1\Demo\43 ETH_UDP 文件夹找到。

接下来,我们进行 UDP 实验,在树莓派 Pico 上使用 MicroPytho 控制 Wiznet W5500 以太网模块监听 UDP 数据包,并将接收到的数据原样返回给发送方,示例代码如下:

Python 复制代码
# Python env   : MicroPython v1.23.0 on Wiznet W5500
# -*- coding: utf-8 -*-        
# @Time    : 2024/8/8 下午2:28   
# @Author  : 李清水            
# @File    : main.py       
# @Description : 以太网类实验,进行UDP协议测试

# ======================================== 导入相关模块 ========================================

# 导入用于创建和管理网络连接的套接字模块
from usocket import socket, AF_INET, SOCK_DGRAM
# 导入硬件相关模块
from machine import Pin,SPI
# 导入时间相关模块
import time
# 导入网络相关模块
import network

# ======================================== 全局变量 ============================================

# 设备IP地址
ip = '192.168.1.20'
sn = '255.255.255.0'
gw = '192.168.1.1'
dns= '8.8.8.8'

# 用于网络连接的元组对象
netinfo=(ip, sn, gw, dns)
# 监听端口
localport = 8000

# ======================================== 功能函数 ============================================

# 初始化网络接口
def w5x00_init() -> network.WIZNET5K:
    """
​    初始化 network.WIZNET5K 实例,设置静态 IP 地址并进行网络连接。

​    Args:
​        None

​    Returns:
​        network.WIZNET5K: 初始化并连接成功的 network.WIZNET5K 实例。

​    Raises:
​        None
​    """

​    ​# 声明全局变量
    global localport

    # 初始化SPI对象
    spi = SPI(0, 2_000_000, mosi=Pin(19), miso=Pin(16), sck=Pin(18))
    # 实例化network.WIZNET5K类,传入使用的片选引脚CS和复位引脚RST
    nic = network.WIZNET5K(spi, Pin(17), Pin(20))
    # 激活网络接口
    nic.active(True)
    # 设置静态IP地址:主机地址、子网掩码、网关地址和DNS服务器地址
    nic.ifconfig(netinfo)

    # 若是没有连接网络,则循环执行
    while not nic.isconnected():
        time.sleep(1)
        # 输出寄存器信息
        print(nic.regs())

    # 打印设置的IP地址
    print('ip :', nic.ifconfig()[0])
    print('sn :', nic.ifconfig()[1])
    print('gw :', nic.ifconfig()[2])
    print('dns:', nic.ifconfig()[3])

    # 返回network.WIZNET5K实例
    return nic

def udp_loop(nic: 'network.WIZNET5K') -> None:
    """
​    UDP循环监听,接收并打印UDP数据包。

​    Args:
​        nic (network.WIZNET5K): network.WIZNET5K实例,用于获取网络接口配置。

​    Returns:
​        None: 该函数没有返回值。

​    Raises:
​        None: 该函数不抛出异常。
​    """

​    ​# 声明全局变量
    global localport

    # 创建一个UDP套接字
    # AF_INET 是地址簇(Address Family)的一种,表示使用 IPv4 协议族
    # SOCK_DGRAM 是套接字类型的一种,表示使用UDP协议
    s = socket(AF_INET, SOCK_DGRAM)
    # 绑定套接字到指定的IP地址和端口
    s.bind((nic.ifconfig()[0], localport))
    # 打印打开UDP循环监听的信息,包括IP地址和端口
    print(f"Opened UDP loopback\r\nip:{nic.ifconfig()[0]},port:{localport}")

    # 等待1秒钟,确保套接字准备就绪
    time.sleep(1)

    # 无限循环以持续监听UDP数据包
    while True:
        # 接收最多2048个字节的数据包,返回数据和发送方的地址
        # 阻塞式的调用,即当没有数据可接收时,程序会在此处等待,直到接收到数据为止
        data, addr = s.recvfrom(2048)
        # 打印接收到的数据和发送方的地址
        print(f'Received:{data} from:{addr}')
        # 将接收到的数据发送回发送方
        s.sendto(b'%s' % data, addr)

# ======================================== 自定义类 ============================================

# ======================================== 初始化配置 ==========================================

# 延时3s,等待器件上电
time.sleep(3)
# 打印调试信息
print("FreakStudio : Using W5x00 Ethernet to do UDP Connect Test")

# 初始化w5500模块
nic = w5x00_init()

# ========================================  主程序  ===========================================

# 运行UDP循环
udp_loop(nic)

UDP 服务器主循环 (udp_loop() 函数)中,我们进行如下操作:

  1. 创建 UDP​​套接字 :使用 IPv4 地址簇(AF_INET)和 UDP 协议(SOCK_DGRAM);
  2. 绑定套接字 :将套接字绑定到 W5500IP 地址和指定的端口;
  3. 打印监听信息 :输出当前监听的 IP 地址和端口号;
  4. 等待数据包 :在一个无限循环中,阻塞等待接收 UDP 数据包(recvfrom);
  5. 打印并回传数据 :接收到数据后,打印发送方地址和数据内容,然后将数据发送回发送方(sendto)。

需要注意的是,在 UDP 监听过程中,不需要预先指定发送方的 IP 地址和端口。UDP 服务器只需要绑定自己的本地 IP 地址和端口号,就可以监听并接收来自任何发送方的数据包,并通过 ​**recvfrom()函数获取发送设备的地址信息。**

烧录代码,打开终端,可以看到显示如下信息:

我们打开 NetAssist 软件,选择协议类型为 UDP,配置远程本地地址为电脑

地址(198.168.1.6) ,本地主机端口设置默认即可,为 8080,其余选项均为默认,点击"​**打开**​"按钮:

输入数据,可以看到 Pico 和 w5500 模块正常接收并回传了相关数据。

相关推荐
Freak嵌入式1 小时前
MicroPython 以太网实战:Pico+W5500 TCP 客户端详解
嵌入式
Freak嵌入式1 小时前
MicroPython W5500 以太网实验|ping 测试:原理 + 实操全解析
嵌入式
Freak嵌入式5 小时前
USB-CDC 通信实战应用:树莓派 Pico 虚拟串口 + select+MicroPython 全拆解
嵌入式
Freak嵌入式1 天前
PIO 入门:手把手实现板载 LED 闪烁,原理与代码全解析
嵌入式
Freak嵌入式1 天前
一文搞懂树莓派 Pico 任务调度器:基于定时器的 MicroPython 多任务实现
嵌入式
花 满 楼2 天前
国芯科技CCFC3008PCS BIST (内建自测试) 分析总结
mcu·嵌入式·bist
虎王物联2 天前
ESP32 FreeRTOS多任务优先级翻转与互斥量保护实战
物联网·嵌入式·esp32·freertos
与你4033 天前
CLion 中为什么要重写 _write,而不是 fputc?
嵌入式
Freak嵌入式3 天前
MicroPython 开发避坑:用 Signal 类解决不同电路的电平兼容问题
嵌入式