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_timeoutUDP 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)

浙公网安备 33010602011771号