在 Linux 下用 Rust 做网络相关开发,很多人最先遇到的问题不是怎么写 TcpListener 或 UdpSocket,而是分不清“查看网络状态”“建立网络通信”和“真正修改系统网络配置”分别属于哪一层。本文就按这个顺序重写原始示例:先看接口信息怎么拿,再看 TCP 和 UDP 的典型流程,最后补上错误处理与边界说明,帮助你判断这些代码在项目里能落到什么位置。
获取网络接口信息:先确认程序能看到什么
如果你的目标是让 Rust 程序感知当前机器的网络环境,第一步通常不是直接发包,而是先列出网络接口和地址信息。原文给出的示例就是围绕这个目的展开的。

use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::net::SocketAddr;
use std::os::unix::net::{UnixListener, UnixStream};
use std::os::unix::net::{ToSocketAddrs, FromSocketAddrs};
fn main() {
// 获取所有网络接口
let interfaces = std::net::interfaces().expect("Failed to get network interfaces");
for interface in interfaces {
println!("Interface: {}", interface.name());
// 获取接口的地址
let addrs = interface.addrs().expect("Failed to get addresses for interface");
for addr in addrs {
match addr {
Ok(ipv4) => {
if let IpAddr::V4(ipv4_addr) = ipv4.ip() {
println!("IPv4 Address: {}", ipv4_addr);
}
}
Ok(ipv6) => {
if let IpAddr::V6(ipv6_addr) = ipv6.ip() {
println!("IPv6 Address: {}", ipv6_addr);
}
}
Err(_) => println!("Failed to get address"),
}
}
}
}
这段代码的意图很明确:遍历所有网络接口,输出每个接口对应的 IPv4 和 IPv6 地址。对排查本机地址、绑定监听地址、确认容器或虚拟机网络环境,这类信息都很实用。
这段代码实际解决了什么问题
它解决的是“读取网络接口信息”,而不是“修改 Linux 网络配置”。也就是说,这类代码适合做环境探测、服务启动前检查、日志打印,或者在多网卡场景中帮助程序选择绑定地址。
需要注意的边界
原文把这部分称为“网络设置”,但从代码本身看,它更接近网络信息读取。像设置 IP 地址、子网掩码、默认网关这类操作,通常还需要调用系统命令、netlink、系统 API,或者依赖专门的第三方库;仅靠下面这些标准网络通信接口,并不能直接完成整套 Linux 网络配置。
配置 TCP 连接:Rust 里最常见的服务端写法
如果你的程序需要监听端口、接收客户端连接,再读取数据并返回响应,那么 TCP 是最典型的入口。原文示例保留了一个基础服务端流程。
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
fn main() {
// 监听本地端口
let listener = TcpListener::bind("127.0.0.1:7878").expect("Failed to bind to address");
for stream in listener.incoming() {
match stream {
Ok(mut stream) => {
println!("New connection: {}", stream.peer_addr().unwrap());
// 读取数据
let mut buffer = [0; 1024];
match stream.read(&mut buffer) {
Ok(bytes_read) => {
println!("Received {} bytes: {}", bytes_read, String::from_utf8_lossy(&buffer[..bytes_read]));
}
Err(e) => println!("Failed to read from stream: {}", e),
}
// 发送响应
let response = "Hello, client!";
if let Err(e) = stream.write_all(response.as_bytes()) {
println!("Failed to write to stream: {}", e);
}
}
Err(e) => println!("Failed to accept connection: {}", e),
}
}
}
整个流程可以概括成 4 步:bind 绑定地址和端口,incoming() 循环接收连接,read 读取客户端数据,再用 write_all 返回响应。
为什么这个流程适合作为入门模板
因为它几乎覆盖了 TCP 服务端最基础的骨架:监听、接入、收包、回包。无论后续要接 HTTP、自定义协议还是内部调试接口,基本都要从这个结构演化出来。
在 Linux 上使用时要关注什么
这里绑定的是 127.0.0.1:7878,意味着程序只监听本机回环地址,外部机器无法直接访问。如果你打算让局域网或公网客户端连接,监听地址就要按实际场景调整;同时也要确认端口占用、防火墙规则以及运行权限是否允许绑定对应地址。
配置 UDP 连接:适合轻量消息收发
和 TCP 相比,UDP 不需要建立连接,代码路径也更短。原文给出的示例主要展示了本地绑定、目标地址解析、发送数据和接收返回数据这几个动作。

use std::net::{UdpSocket, SocketAddr};
fn main() {
// 绑定到本地端口
let socket = UdpSocket::bind("127.0.0.1:7878").expect("Failed to bind to address");
// 目标地址
let target_addr: SocketAddr = "127.0.0.1:8080".parse().expect("Failed to parse target address");
// 发送数据
let message = "Hello, UDP server!";
if let Err(e) = socket.send_to(message.as_bytes(), &target_addr) {
println!("Failed to send message: {}", e);
}
// 接收数据
let mut buffer = [0; 1024];
match socket.recv_from(&mut buffer) {
Ok((bytes_received, src_addr)) => {
println!("Received {} bytes from {}: {}", bytes_received, src_addr, String::from_utf8_lossy(&buffer[..bytes_received]));
}
Err(e) => println!("Failed to receive message: {}", e),
}
}
这类写法适合做简单的消息收发、局域网广播类工具、轻量探测程序,或者一些对实时性更敏感、能接受丢包的场景。
UDP 和 TCP 的关键区别
UDP 没有连接建立过程,所以不会像 TCP 那样维护会话状态。调用 send_to 就能直接发,调用 recv_from 就能接,并且接收时还能同时拿到发送方地址,这对做双向通信或简单应答很方便。
写 UDP 程序时别忽略这些问题
代码看起来比 TCP 简单,但这不代表业务上更省心。UDP 天然可能出现丢包、乱序、重复包,应用层如果需要可靠性,往往还得自己补上重试、超时、去重等逻辑。
错误处理:网络代码真正决定稳定性的部分
原文最后提到,所有示例都通过 expect、match 处理了错误。这一点很关键,因为网络程序最常见的问题往往不在“能不能跑”,而在“异常出现时会不会直接崩”。
示例里已经覆盖了哪些常见错误
从现有代码可以看到几类典型失败点:绑定地址失败、地址解析失败、读取失败、写入失败,以及接收连接失败。这些都属于网络编程里高频出现的错误位置。
实际项目里可以再往前走一步
如果只是示例程序,expect 足够直接;但在生产代码里,通常应该把错误分得更细。比如临时性错误可以重试,永久性错误则应记录日志并退出。Rust 的 Result 和 ? 运算符很适合把这类错误传播路径整理得更清楚。
如何理解这篇示例的实际价值
综合来看,原文中的 Rust 示例更准确的定位是“Linux 下的网络信息读取与基础通信”,而不是完整意义上的“系统网络设置”。如果你要做的是服务监听、客户端通信、接口信息探测,这些代码已经能作为起点;如果你要真正修改 Linux 的 IP、路由、网关等配置,就还需要进一步接入系统层能力。
把这个边界先分清,再决定是继续使用 std::net,还是引入系统调用和第三方库,后面的工程路线就会清晰很多。









