Rust嵌入式网络库embassy-net的使用,异步TCP/IP协议栈实现轻量级物联网设备通信
Rust嵌入式网络库embassy-net的使用,异步TCP/IP协议栈实现轻量级物联网设备通信
embassy-net介绍
embassy-net
是一个无标准库(std)、无内存分配(no-alloc)的异步网络栈,专为嵌入式系统设计。
它基于smoltcp构建,提供了更高层次、更规范的API。它将smoltcp提供的组件粘合在一起,处理低级细节,使用为嵌入式系统设计的默认值和内存管理,旨在提供更"开箱即用"的体验。
特性
- IPv4, IPv6支持
- 以太网和裸IP介质
- TCP, UDP, DNS, DHCPv4
- TCP sockets实现了embedded-io异步特性
- 组播支持
硬件支持
- esp-wifi:用于ESP32芯片的WiFi支持
- cyw43:用于Raspberry Pi Pico W中的CYW43xx芯片的WiFi支持
- embassy-usb:支持USB以太网(CDC NCM)
- embassy-stm32:支持STM32芯片的内置以太网MAC
- embassy-net-wiznet:支持Wiznet SPI以太网MAC+PHY芯片(W5100S, W5500)
- embassy-net-esp-hosted:使用ESP32芯片作为非ESP32 MCU的WiFi适配器
完整示例代码
以下是一个使用embassy-net实现TCP客户端连接的完整示例:
use embassy_net::{Stack, Config, DhcpConfig, StaticConfig};
use embassy_net::tcp::TcpSocket;
use embassy_net::driver::Driver;
use embassy_time::{Duration, Timer};
use core::str::FromStr;
#[embassy_executor::task]
async fn net_task(stack: &'static Stack<Driver>) {
stack.run().await
}
#[embassy_executor::task]
async fn tcp_client_task(stack: &'static Stack<Driver>) {
let mut rx_buffer = [0; 4096];
let mut tx_buffer = [0; 4096];
loop {
// Wait for DHCP to assign IP address
while stack.config_v4().is_none() {
Timer::after(Duration::from_secs(1)).await;
}
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
// Connect to server
let remote_endpoint = (Ipv4Address::from_str("192.168.1.100").unwrap(), 8000);
socket.connect(remote_endpoint).await.unwrap();
// Send data
socket.write_all(b"Hello from embassy-net!").await.unwrap();
// Read response
let mut buf = [0; 1024];
let n = socket.read(&mut buf).await.unwrap();
info!("Received {} bytes: {:?}", n, &buf[..n]);
socket.close().await;
Timer::after(Duration::from_secs(10)).await;
}
}
#[embassy_executor::main]
async fn main(spawner: embassy_executor::Spawner) {
// Initialize network driver (this depends on your hardware)
let driver = init_network_driver();
// Create network stack
let config = Config::Dhcp(DhcpConfig {
hostname: Some("embassy-net-example".into()),
..Default::default()
});
let stack = &*Box::leak(Box::new(Stack::new(
driver,
config,
embassy_net::stack::StackResources::new(),
seed,
)));
// Spawn network task
spawner.spawn(net_task(stack)).unwrap();
// Spawn TCP client task
spawner.spawn(tcp_client_task(stack)).unwrap();
}
添加对新硬件的支持
要为新硬件添加embassy-net支持(如新的以太网或WiFi芯片),你需要实现embassy-net-driver特性。
互操作性
这个crate可以在任何执行器上运行。它使用embassy-time进行时间记录和超时处理。
1 回复
embassy-net: Rust嵌入式网络库的异步TCP/IP协议栈实现
介绍
embassy-net是Rust生态中专门为嵌入式设备设计的异步网络协议栈,属于embassy嵌入式运行时的一部分。它为资源受限的物联网设备提供了轻量级的TCP/IP网络功能实现,具有以下特点:
- 专为嵌入式系统优化,内存占用小
- 纯Rust实现,无unsafe代码
- 基于async/await的异步API
- 支持以太网和WiFi等常见接口
- 包含ARP、IPv4、ICMP、TCP和UDP等协议实现
基本使用方法
添加依赖
首先在Cargo.toml中添加依赖:
[dependencies]
embassy-net = { version = "0.1", features = ["tcp", "udp"] }
embassy-executor = { version = "0.1" }
embassy-time = { version = "0.1" }
初始化网络栈
use embassy_net::{Stack, Config};
use embassy_net::driver::Driver;
use embassy_net::wire::{Ipv4Address, Ipv4Cidr};
// 假设有一个实现了Driver trait的网卡驱动实例
let driver = MyNetworkDriver::new();
// 配置网络参数
let config = Config::ipv4_static(embassy_net::StaticConfigV4 {
address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 100), 24),
dns_servers: Vec::new(),
gateway: Some(Ipv4Address::new(192, 168, 1, 1)),
});
// 创建网络栈
let stack = Stack::new(driver, config);
TCP服务器示例
use embassy_net::tcp::TcpSocket;
use embassy_net::IpEndpoint;
#[embassy_executor::task]
async fn tcp_server_task(stack: &'static Stack<MyNetworkDriver>) {
let mut rx_buffer = [0; 4096];
let mut tx_buffer = [0; 4096];
loop {
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
socket.listen(8080).unwrap();
let (mut socket, remote_endpoint) = socket.accept().await.unwrap();
log::info!("Connection from {}", remote_endpoint);
loop {
let n = socket.read(&mut rx_buffer).await.unwrap();
if n == 0 {
break;
}
log::info!("Received {} bytes: {:?}", n, &rx_buffer[..n]);
socket.write_all(&rx_buffer[..n].await.unwrap();
}
}
}
TCP客户端示例
#[embassy_executor::task]
async fn tcp_client_task(stack: &'static Stack<MyNetworkDriver>) {
let mut rx_buffer = [0; 4096];
let mut tx_buffer = [0; 4096];
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
let remote_endpoint = IpEndpoint::new(Ipv4Address::new(192, 168, 1, 1), 8080);
socket.connect(remote_endpoint).await.unwrap();
let message = b"Hello from embassy-net!";
socket.write_all(message).await.unwrap();
let n = socket.read(&mut rx_buffer).await.unwrap();
log::info!("Received echo: {:?}", &rx_buffer[..n]);
}
UDP示例
use embassy_net::udp::UdpSocket;
#[embassy_executor::task]
async fn udp_task(stack: &'static Stack极简嵌入式网络应用完整示例:
```rust
use embassy_executor::Spawner;
use embassy_net::{Stack, Config};
use embassy_net::driver::Driver;
use embassy_net::wire::{Ipv4Address, Ipv4Cidr};
use embassy_net::tcp::TcpSocket;
use embassy_net::IpEndpoint;
use log::info;
// 定义网络驱动类型
struct MyNetworkDriver;
impl Driver for MyNetworkDriver {
// 实现必要的驱动方法
// ...
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
// 初始化日志
env_logger::init();
// 创建网络驱动实例
let driver = MyNetworkDriver;
// 配置静态IP
let config = Config::ipv4_static(embassy_net::StaticConfigV4 {
address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 100), 24),
dns_servers: Vec::new(),
gateway: Some(Ipv4Address::new(192, 168, 1, 1)),
});
// 创建网络栈
let stack = &*Box::leak(Box::new(Stack::new(driver, config)));
// 启动网络任务
spawner.spawn(network_task(stack)).unwrap();
// 启动TCP服务器
spawner.spawn(tcp_server_task(stack)).unwrap();
// 启动TCP客户端(演示用)
spawner.spawn(tcp_client_task(stack)).unwrap();
}
#[embassy_executor::task]
async fn network_task(stack: &'static Stack<MyNetworkDriver>) {
stack.run().await
}
#[embassy_executor::task]
async fn tcp_server_task(stack: &'static Stack<MyNetworkDriver>) {
let mut rx_buffer = [0; 1024];
let mut tx_buffer = [0; 1024];
loop {
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
socket.listen(8080).unwrap();
let (mut socket, remote_endpoint) = socket.accept().await.unwrap();
info!("Connection from {}", remote_endpoint);
loop {
let n = socket.read(&mut rx_buffer).await.unwrap();
if n == 0 { break; }
info!("Received {} bytes", n);
socket.write_all(&rx_buffer[..n]).await.unwrap();
}
}
}
#[embassy_executor::task]
async fn tcp_client_task(stack: &'static Stack<MyNetworkDriver>) {
let mut rx_buffer = [0; 1024];
let mut tx_buffer = [0; 1024];
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
let remote = IpEndpoint::new(Ipv4Address::new(192, 168, 1, 100), 8080);
socket.connect(remote).await.unwrap();
socket.write_all(b"Ping").await.unwrap();
let n = socket.read(&mut rx_buffer).await.unwrap();
info!("Received echo: {:?}", &rx_buffer[..n]);
}
注意事项
- embassy-net需要与embassy-executor运行时配合使用
- 需要提供实现了Driver trait的底层网络驱动
- 缓冲区大小需要根据设备资源情况合理配置
- 目前主要支持IPv4,IPv6支持还在开发中
embassy-net为嵌入式设备提供了简单易用的网络功能,特别适合需要轻量级TCP/IP协议栈的物联网应用场景。