std::net::UdpSocket

UdpSocket

bind

创建一个UDP套接字,返回Result<UdpSocket>

绑定端口

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
    println!("{:?}", socket);
}
UdpSocket { addr: 127.0.0.1:3400, fd: 3 }

绑定端口(选择)

use std::net::{SocketAddr, UdpSocket};

fn main() {
    let addrs = [
        SocketAddr::from(([127, 0, 0, 1], 3400)),
        SocketAddr::from(([127, 0, 0, 1], 3401)),
    ];
    let socket = UdpSocket::bind(&addrs[..]).expect("couldn't bind to address");
    println!("socket: {:?}", socket);
}
socket: UdpSocket { addr: 127.0.0.1:3400, fd: 3 }

connect

UDP 套接字连接到远程地址(不会建立连接,只是在本地设置目标地址)

允许使用 send 和 recv 系统调用来发送数据

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
    socket..connect(("127.0.0.1", 9999));
  	// socket.send和socket.recv收发数据
}

take_erroe

取出内核Socket缓存的异步错误,取完就清空

  • ConnectionRefused(连接拒绝)

    • 找的到主机,端口没有使用

    • 对方端口不存在

    • 对方没启动

    • ICMP 端口不可达

  • HostUnreachable(主机不可达)

    • 主机不存在

    • 路由不可达

  • NetworkUnreachable(网络不可达)

    • 找不到主机
  • MessageTooBig(数据包太大)

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
		// 连接一个没有使用的端口
    socket.connect(("127.0.0.1", 9999));
  
	  // 发现端口不可达 → 记录ICMP错误
    socket.send(b"hello world\n").unwrap();

    println!("connected to server:{:?}", socket.take_error());
}
connected to server:Ok(Some(Os { code: 61, kind: ConnectionRefused, message: "Connection refused" }))

收发数据

发送数据

send

只能发给connect过的目标

返回Result<usize>

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");

    let _ = socket.connect(("127.0.0.1", 9999));
		
  	// socket.send(b"hello world\n").unwrap();成功直接返回发送字节数
    let send_result = socket.send(b"hello world\n");

    println!("send_result: {:?}", send_result);
}
send_result: Ok(12)

send_to

可以发给任何人,每次指定地址

返回Result<usize>

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
		// socket.send_to("hello world".as_bytes(), "127.0.0.1:3400").unwrap();成功直接返回发送字节数
    let send_result = socket.send_to("hello world".as_bytes(), "127.0.0.1:3400");

    println!("send_result: {:?}", send_result);
}
Ok(11)

接受数据

阻塞等待数据

recv

只能发给connect过的目标

只拿数据,不知道谁发的

返回Result<usize>

发送端
use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:9999").unwrap();
    let buf = b"hello";
    socket.send_to(buf, "127.0.0.1:3400").unwrap();
}
接收端
use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");

    let _ = socket.connect(("127.0.0.1", 9999));

    let mut buf = vec![0; 1024];
    let recv_num = socket.recv(&mut buf).expect("Didn't receive data");

    println!("buf: {:?}", &buf[..recv_num]);
}
buf: [104, 101, 108, 108, 111]

recv_from

可以获取所有bind端口的数据包

拿数据 + 发送方的 IP + 端口

返回Result<(usize, SocketAddr>

发送端
use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:9999").unwrap();
    let buf = b"hello";
    socket.send_to(buf, "127.0.0.1:3400").unwrap();
}
接受端
use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");

    let mut buf = vec![0; 1024];
    let (recv_num, addr) = socket.recv_from(&mut buf).expect("Didn't receive data");

    println!("buf: {:?}", &buf[..recv_num]);
    println!("addr: {:?}", addr);
}
buf: [104, 101, 108, 108, 111]
addr: 127.0.0.1:9999

查看数据

peek和peek_from偷看数据,读完还在。阻塞等待数据

不消耗数据

peek

只能查看connect过的目标

返回Result<usize>

发送端

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:9999").unwrap();
    let buf = b"hello";
    socket.send_to(buf, "127.0.0.1:3400").unwrap();
}

接收端

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");

    let _ = socket.connect(("127.0.0.1", 9999));

    let mut peek_buf = vec![0; 1024];

    let s = socket.peek(&mut peek_buf);
    match s {
        Ok(size) => {
            println!("read {} bytes: {:?}", size, &peek_buf[..size]);
        },
        Err(e) => {
            println!("error: {:?}", e);
        }
    }

    let mut buf = vec![0; 1024];
    let recv_num = socket.recv(&mut buf).expect("Didn't receive data");

    println!("buf: {:?}", &buf[..recv_num]);
}
read 5 bytes: [104, 101, 108, 108, 111]
buf: [104, 101, 108, 108, 111]

peek_from

可以查看任意bind端口的数据包

返回Result<(usize, SocketAddr>

发送端

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:9999").unwrap();
    let buf = b"hello";
    socket.send_to(buf, "127.0.0.1:3400").unwrap();
}

接收端

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");

    let mut peek_buf = vec![0; 1024];

    let s = socket.peek_from(&mut peek_buf);
    match s {
        Ok((size, addr)) => {
            println!("addr {}", addr);
            println!("read {} bytes: {:?}", size, &peek_buf[..size]);
        },
        Err(e) => {
            println!("error: {:?}", e);
        }
    }

    let mut buf = vec![0; 1024];
    let recv_num = socket.recv(&mut buf).expect("Didn't receive data");

    println!("buf: {:?}", &buf[..recv_num]);
}
addr 127.0.0.1:9999
read 5 bytes: [104, 101, 108, 108, 111]
buf: [104, 101, 108, 108, 111]

查看地址

local_addr

查看自己的ip+端口

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");

    println!("{:?}", socket.local_addr());
}
Ok(127.0.0.1:3400)

peer_addr

查看对方的ip+端口

必须是 connect 过的

没有connect连接

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");

    println!("{:?}", socket.peer_addr());
}
Err(Os { code: 57, kind: NotConnected, message: "Socket is not connected" })

connect连接

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
    let _ = socket.connect("127.0.0.1:9999");
    println!("{:?}", socket.peer_addr());
}
Ok(127.0.0.1:9999)

超时设置

读取超时设置

socket.set_read_timeout

use std::net::UdpSocket;
use std::time::Duration;


fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
    socket.set_read_timeout(Some(Duration::from_secs(2))).unwrap();

    let mut buf = [0; 1500];
    let result = socket.recv_from(&mut buf);
    match result {
        Ok((num, addr)) => {
            println!("Received {} bytes from {}", num, addr);
        },
        Err(e) => {
            println!("err: {:?}", e);
        }
    }
}
err: Os { code: 35, kind: WouldBlock, message: "Resource temporarily unavailable" }

发送超时

socket.set_write_timeout

UDP send /send_to 几乎永远不会阻塞

  • 队列没满 → 从不阻塞
  • 队列满了 → 直接丢包,也不阻塞
use std::net::UdpSocket;
use std::time::Duration;


fn main() {
    let socket = UdpSocket::bind("127.0.0.1:3400").expect("couldn't bind to address");
    socket.set_write_timeout(Some(Duration::from_micros(1))).unwrap();

    let mut buf = [0; 1024];
    loop {
        let result = socket.send_to(&mut buf, "127.0.0.1:9999");
        match result {
            Ok(len) => {
                println!("send: {}", len);
            },
            Err(e) => {
                println!("send failed {}", e);
                break;
            }
        }

    }
}

设置广播包

socket.set_broadcast(true)

发送端

  • 端口

    • 必须指定端口
  • ip内容(根据子网掩码决定)

    • 255.255.255.255:9999

      • 给全网段的9999端口广播
      • 如果网关是192.168.0.1/24,那么255.255.255.255相当于192.168.0.x地址
      • 如果网关是192.168.0.1/16,那么255.255.255.255相当于192.168.x.x地址
    • 192.168.255.255:8000

      • 如果网关是192.168.0.1/16,那么192.168.255.255相当于192.168.x.x的8000端口广播(本网广播 )
      • 如果网关是192.168.0.1/24,那么192.168.255.255相当于``192.168.255.x`是无效的(不是本网广播 )
use std::net::UdpSocket;
use std::time::Duration;


fn main() {
    // 本机地址是192.168.0.105
    let socket = UdpSocket::bind("192.168.0.105:3400").expect("couldn't bind to address");
    // 设置广播
    socket.set_broadcast(true).expect("couldn't set broadcast");
    // 像192.168.0.x:9999的端口发送数据
    socket.send_to(b"hello", "192.168.0.255:9999").expect("couldn't send hello");
}

接收端

接收端必须监听0.0.0.0本机地址

  • 所有设备都有自己的本机ip,所以监听0.0.0.0
    • 广播范围是根据子网掩码决定
    • 设备ip是192.168.0./24,那么就能接受192.168.0.255:9999的内容
    • 同个设备ip只能绑定一个端口UdpSocket::bind("0.0.0.0:9999")
  • UdpSocket::bind("192.168.0.105:9999")那么只会接受指定的数据,广播数据收不到
use std::net::UdpSocket;

fn main() {
    // let socket = UdpSocket::bind("192.168.0.105:9999").unwrap();
    let socket = UdpSocket::bind("0.0.0.0:9999").unwrap();
    let mut buf = [0;1024];
    let (size, addr) = socket.recv_from(&mut buf).unwrap();
    println!("buf: {:?}", &buf[..size]);
    println!("addr: {}", addr);
}
buf: [104, 101, 108, 108, 111]
addr: 192.168.0.105:3400

非阻塞模式

socket.set_nonblocking(true)

  • 效果

    • 没有数据 → 立刻返回错误(WouldBlock)

    • 有数据 → 立刻返回数据

  • 场景

    • 边收广播,一边做别
    • GUI / 游戏程序

模版

loop {
    // 不卡住,立刻检查有没有数据
    match socket.recv_from(&mut buf) {
        Ok(..) => println!("收到广播"),
        Err(..) => println!("暂无数据,继续运行"),
    }

    // 这里的代码 每次循环都会执行
    do_other_thing();
}

查看错误信息

use std::net::UdpSocket;

fn main() {
    let socket = UdpSocket::bind("0.0.0.0:9999").unwrap();
    socket.set_nonblocking(true).unwrap();
    loop {
        let mut buf = [0; 1024];
        let result = socket.recv_from(&mut buf);
        match result {
            Ok((size, addr)) => {
                println!("Received {} bytes from {}", size, addr);
            },
            Err(e) => {
                println!("err: {}", e);
                break;
            }
        }
    }
}
err: Resource temporarily unavailable (os error 35)
posted @ 2026-04-21 23:06  lxd670  阅读(18)  评论(0)    收藏  举报