2个版本
0.1.1 | 2019年10月16日 |
---|---|
0.1.0 | 2019年10月16日 |
#10 in #rtt
25KB
344 行
塞尔达
塞尔达是一个用于实时应用程序的轻量级应用层网络协议。它基于UDP,提供轻量级虚拟连接和往返时间估计。API灵感来源于laminar。
塞尔达不提供任何可靠性,而是开发用来与其他可靠协议(例如TCP)一起使用或在顶部添加可靠性层。
功能
- 虚拟连接
- 线程安全的发送/接收
- RTT估计
- 立即确认支持(RTT估计)
快速启动
use std::net::SocketAddr;
use crossbeam::channel::{Sender, Receiver};
use zelda::{Socket, Config, Packet, Event};
let socket_address: SocketAddr = "127.0.0.1:38000".parse().unwrap();
let socket1 = Socket::bind(socket_address, Config::default())?;
let socket2 = Socket::bind_any(Config::default())?;
println!("Address of socket 2: {}", socket2.local_address());
let packet_sender: Sender<Packet> = socket2.packet_sender();
packet_sender.send(Packet::new(socket_address, "Hello, Client!".as_bytes().to_vec()));
let event_receiver: Receiver<Event> = socket1.event_receiver();
while let Ok(event) = event_receiver.recv() {
Event::Connected(addr) => {
// A connection was established with addr.
},
Event::Received { address, payload, rtt, rtt_offset } => {
// Received payload on addr with estimated rtt.
},
Event::Disconnected(addr) => {
// Client with addr disconnected.
break;
}
}
另一个完整示例
let server_address: SocketAddr = "127.0.0.1:38000".parse().unwrap();
let client_address: SocketAddr = "127.0.0.1:38001".parse().unwrap();
let server = Socket::bind(server_address, Config::default()).unwrap();
let client = Socket::bind(client_address, Config::default()).unwrap();
let j1 = std::thread::spawn(move || {
for _ in 0..20 {
server.packet_sender().send(Packet::new(client_address, "Hello, Client!".as_bytes().to_vec())).unwrap();
std::thread::sleep(std::time::Duration::from_millis(20));
}
loop {
match server.event_receiver().recv() {
Ok(Event::Connected(addr)) => {
println!("Client connected to server!");
assert_eq!(addr, client_address);
},
Ok(Event::Received { address, payload, rtt, rtt_offset }) => {
println!("Server received content: {}, estimated RTT: {} ms, has estimate: {}", std::str::from_utf8(&payload).unwrap(), rtt.unwrap_or_default().as_millis(), rtt.is_some());
assert_eq!(addr, client_address);
assert_eq!("Hello, Server!".as_bytes().to_vec(), payload);
},
Ok(Event::Disconnected(addr)) => {
println!("Client disconnnected from server!");
assert_eq!(addr, client_address);
break;
},
Err(err) => {
panic!("Error: {}", err);
}
}
}
});
let j2 = std::thread::spawn(move || {
for _ in 0..20 {
client.packet_sender().send(Packet::new(server_address, "Hello, Server!".as_bytes().to_vec())).unwrap();
std::thread::sleep(std::time::Duration::from_millis(20));
}
loop {
match client.event_receiver().recv() {
Ok(Event::Connected(addr)) => {
println!("Server connected to client!");
assert_eq!(addr, server_address);
},
Ok(Event::Received { address, payload, rtt, rtt_offset }) => {
println!("Client received content: {}, estimated RTT: {} ms, has estimate: {}", std::str::from_utf8(&payload).unwrap(), rtt.unwrap_or_default().as_millis(), rtt.is_some());
assert_eq!(addr, server_address);
assert_eq!("Hello, Client!".as_bytes().to_vec(), payload);
},
Ok(Event::Disconnected(addr)) => {
println!("Server disconnnected from client!");
assert_eq!(addr, server_address);
break;
},
Err(err) => {
panic!("Error: {}", err);
}
}
}
});
j1.join().unwrap();
j2.join().unwrap();
模拟网络条件
塞尔达不包含链路条件器,而是应该使用如netem的单独程序来模拟链路条件。
在Linux上使用netem
设置100ms延迟和20ms正态分布的变化
tc qdisc change dev <interface-name> root netem delay 100ms 20ms distribution normal
有关更多选项,请参阅netem文档。
依赖关系
~2–2.8MB
~53K SLoC