5个版本
0.3.4 | 2023年8月13日 |
---|---|
0.3.3 | 2023年8月13日 |
0.3.2 | 2023年5月2日 |
0.3.1 | 2023年5月2日 |
0.3.0 | 2023年5月1日 |
269 在 数据结构 中
每月下载量 34
在 rak-rs 中使用
84KB
1.5K SLoC
binary-util
一个无panic的二进制工具包,用于在网络上读写二进制流。
BinaryUtils提供以下功能
binary_util::io
,用于手动读取和写入流。binary_util::interfaces
,允许自动化读取数据结构。binary_util::BinaryIo
,用于自动实现binary_util::interfaces::Reader
和binary_util::interfaces::Writer
。binary_util::types
,用于读取和写入非原始类型,如u24
和varint
。
入门指南
Binary Utils可在 crates.io 上找到,请在您的 Cargo.toml
中添加以下内容
[dependencies]
binary_util = "0.3.4"
可选地,如果您想移除 derive
功能,您可以在您的 Cargo.toml
中添加以下内容
[dependencies]
binary_util = { version = "0.3.4", default-features = false }
要显式启用 derive,您可以使用
[dependencies]
binary_util = { version = "0.3.0", default-features = false, features = ["derive"] }
二进制IO
《io》模块提供了一种连续读写二进制数据的方式,同时确保无panic。该模块提供了两个结构体,分别是ByteReader
和ByteWriter
,它们分别是对bytes::Buf
和bytes::BufMut
的封装。通常情况下,当您需要手动读写二进制数据时,会使用ByteReader
和ByteWriter
。
读取示例:以下示例展示了如何从流中读取一个varint。
use binary_util::io::ByteReader;
const BUFFER: &[u8] = &[255, 255, 255, 255, 7]; // 2147483647
fn main() {
let mut buf = ByteReader::from(&BUFFER[..]);
buf.read_var_u32().unwrap();
}
写入示例:以下示例展示了如何将字符串写入流。
use binary_util::io::ByteWriter;
fn main() {
let mut buf = ByteWriter::new();
buf.write_string("Hello world!");
}
实际案例:此模块的一个更实际的应用案例可能是一个简单的pong服务器,其中包含两个数据包,分别是Ping
和Pong
,它们通过UDP分别转发。以下示例使用ByteReader
和ByteWriter
,利用std::net::UdpSocket
发送和接收数据包。
use binary_util::io::{ByteReader, ByteWriter};
use std::net::UdpSocket;
pub struct PingPacket {
pub time: u64
}
pub struct PongPacket {
pub time: u64,
pub ping_time: u64
}
fn main() -> std::io::Result<()> {
let socket = UdpSocket::bind("127.0.0.1:5000")?;
let mut buf = [0; 1024];
loop {
let (amt, src) = socket.recv_from(&mut buf)?;
let mut buf = ByteReader::from(&buf[..amt]);
match buf.read_u8()? {
0 => {
let ping = PingPacket {
time: buf.read_var_u64()?
};
println!("Received ping from {}", src);
let mut writer = ByteWriter::new();
let pong = PongPacket {
time: std::time::SystemTime::now()
.duration_since(
std::time::UNIX_EPOCH
)
.unwrap()
.as_millis() as u64,
ping_time: ping.time
};
// Write pong packet
writer.write_u8(1);
writer.write_var_u64(pong.time);
writer.write_var_u64(pong.ping_time);
socket.send_to(writer.as_slice(), src)?;
},
1 => {
let pong = PongPacket {
time: buf.read_var_u64()?,
ping_time: buf.read_var_u64()?
};
println!(
"Received pong from {} with ping time of {}ms",
src,
pong.time - pong.ping_time
);
}
_ => {
println!("Received unknown packet from {}", src);
}
}
}
}
接口
《interfaces》模块提供了一种使用两个特质,Reader
和Writer
,来实现读写二进制数据的方法。通常情况下,在实现枚举或结构体时,会使用BinaryIo
;但在您需要实现一个可能不兼容BinaryIo
的类型时,可以使用这些特质。
示例:以下示例为HelloPacket
实现了Reader
和Writer
特质,允许它与BinaryIo
一起使用;此示例还允许您使用更简单的约定读写数据包。
use binary_util::interfaces::{Reader, Writer};
use binary_util::io::{ByteReader, ByteWriter};
pub struct HelloPacket {
pub name: String,
pub age: u8,
pub is_cool: bool,
pub friends: Vec<String>
}
impl Reader<HelloPacket> for HelloPacket {
fn read(buf: &mut ByteReader) -> std::io::Result<Self> {
Ok(Self {
name: buf.read_string()?,
age: buf.read_u8()?,
is_cool: buf.read_bool()?,
friends: Vec::<String>::read(buf)?
})
}
}
impl Writer<HelloPacket> for HelloPacket {
fn write(&self, buf: &mut ByteWriter) -> std::io::Result<()> {
buf.write_string(&self.name);
buf.write_u8(self.age);
buf.write_bool(self.is_cool);
self.friends.write(buf)?;
Ok(())
}
}
通过上述示例,现在您可以使用BinaryIo
读取和写入数据包,同时还可以使用现在已实现的read
和write
方法更轻松地进行读写。
fn main() {
let mut buf = ByteWriter::new();
let packet = HelloPacket {
name: "John".to_string(),
age: 18,
is_cool: true,
friends: vec!["Bob".to_string(), "Joe".to_string()]
};
buf.write_type(&packet).unwrap();
}
类型
《types》模块提供了一种使用BinaryIo
派生宏实现非原始类型的方法。
本模块提供了以下辅助类型
varu32
(https://docs.rs/binary-util/latest/binary_util/types/struct.varu32.html - 无符号32位可变长度整数vari32
(https://docs.rs/binary-util/latest/binary_util/types/struct.vari32.html - 有符号32位可变长度整数varu64
(https://docs.rs/binary-util/latest/binary_util/types/struct.varu64.html - 无符号64位可变长度整数vari64
(https://docs.rs/binary-util/latest/binary_util/types/struct.vari64.html - 有符号64位可变长度整数u24
- 24位无符号整数i24
- 24位有符号整数LE
- 小端类型BE
- 大端类型
通用用法
use binary_util::BinaryIo;
use binary_util::io::{ByteReader, ByteWriter};
use binary_util::types::{varu64, varu32, u24, i24, LE, BE};
#[derive(BinaryIo)]
pub struct ProxyStatusPacket {
pub clients: u24,
pub max_clients: u24,
pub net_download: varu32,
pub net_upload: varu64,
}
fn main() {
let mut buf = ByteWriter::new();
let packet = ProxyStatusPacket {
clients: 10,
max_clients: 100,
net_download: 1000.into(),
net_upload: 1000.into()
};
buf.write_type(&packet).unwrap();
let mut buf = ByteReader::from(buf.as_slice());
let packet = ProxyStatusPacket::read(&mut buf).unwrap();
println!("Clients: {}", packet.clients);
println!("Max Clients: {}", packet.max_clients);
println!("Net Download: {}", packet.net_download.0);
println!("Net Upload: {}", packet.net_upload.0);
}
依赖项
~2.5–4MB
~74K SLoC