我想通过一个发送我的结构TcpStream.我可以发送String或u8,但我不能发送任意结构.例如:
struct MyStruct {
id: u8,
data: [u8; 1024],
}
let my_struct = MyStruct { id: 0, data: [1; 1024] };
let bytes: &[u8] = convert_struct(my_struct); // how??
tcp_stream.write(bytes);
Run Code Online (Sandbox Code Playgroud)
收到数据后,我想转换&[u8]回来MyStruct.如何在这两种表示之间进行转换?
我知道Rust有一个用于序列化数据的JSON模块,但是我不想使用JSON,因为我想尽可能快地发送数据,所以我想要没有或只是非常小的开销.
ide*_*n42 21
使用stdlib和通用函数可以完成正确大小的结构作为零复制字节.
在下面的示例中,有一个可重用的函数,any_as_u8_slice而不是convert_struct,因为这是一个包装转换和切片创建的实用程序.
请注意,问题是关于转换,此示例创建一个只读片,因此具有不需要复制内存的优点.
下面是一个基于这个问题的工作实例:
unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
::std::slice::from_raw_parts(
(p as *const T) as *const u8,
::std::mem::size_of::<T>(),
)
}
fn main() {
struct MyStruct {
id: u8,
data: [u8; 1024],
}
let my_struct = MyStruct { id: 0, data: [1; 1024] };
let bytes: &[u8] = unsafe { any_as_u8_slice(&my_struct) };
// tcp_stream.write(bytes);
println!("{:?}", bytes);
}
Run Code Online (Sandbox Code Playgroud)
注1)即使第三方板条箱在某些情况下可能更好,但这是一个原始操作,它对于知道在Rust中如何做有用.
注2)在撰写本文时(Rust 1.15),不支持const函数.一旦有,就可以投射到固定大小的数组而不是切片.
注3)该any_as_u8_slice函数被标记,unsafe因为任何填充字节struct可能是未初始化的内存(给出未定义的行为).如果有一种方法可以确保输入参数只使用了结构#[repr(packed)],那么它可能是安全的.
否则该函数是相当安全的,因为它可以防止缓冲区溢出,因为输出是只读的,固定的字节数,并且它的生命周期绑定到输入.
如果你想要一个返回a的版本&mut [u8],这将是非常危险的,因为修改可能很容易创建不一致/损坏的数据.
She*_*ter 16
(Renato Zannon对类似问题的评论无耻地被盗)
也许像bincode你的情况一样的解决方案?这是一个有效的摘录:
Cargo.toml
[package]
name = "foo"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
[dependencies]
serde_derive = "1.0.34"
bincode = "1.0.0"
serde = "1.0.34"
Run Code Online (Sandbox Code Playgroud)
main.rs
extern crate bincode;
#[macro_use]
extern crate serde_derive;
extern crate serde;
use std::fs::File;
#[derive(Serialize, Deserialize)]
struct A {
id: i8,
key: i16,
name: String,
values: Vec<String>,
}
fn main() {
let a = A {
id: 42,
key: 1337,
name: "Hello world".to_string(),
values: vec!["alpha".to_string(), "beta".to_string()],
};
// Encode to something implementing Write
let mut f = File::create("/tmp/output.bin").unwrap();
bincode::serialize_into(&mut f, &a).unwrap();
// Or just to a buffer
let bytes = bincode::serialize(&a).unwrap();
println!("{:?}", bytes);
}
Run Code Online (Sandbox Code Playgroud)
然后,您就可以在任何地方发送字节.我假设您已经意识到天真地发送字节的问题(如潜在的字节序问题或版本控制),但我会在以下情况下提及它们^ _ ^.
您可以使用bytemuck板条箱安全地完成此操作:
#[derive(bytemuck::NoUninit, Clone, Copy)]
#[repr(C)]
struct MyStruct {
id: u8,
data: [u8; 1024],
}
let my_struct = MyStruct { id: 0, data: [1; 1024] };
let bytes: &[u8] = bytemuck::bytes_of(&my_struct);
tcp_stream.write(bytes);
Run Code Online (Sandbox Code Playgroud)
请注意,这要求结构为Copyand #[repr(C)]or #[repr(transparent)]。
| 归档时间: |
|
| 查看次数: |
7810 次 |
| 最近记录: |