gpt4 book ai didi

rust - 将数据包读入 Rust 中的结构

转载 作者:行者123 更新时间:2023-12-03 11:25:59 25 4
gpt4 key购买 nike

1。问题总结。

  • 我正在尝试将 UDP 数据包数据从套接字读取到 Rust 中的结构中。
  • 我的大部分谷歌搜索都指向了外部 crate 的方向来进行解析。这似乎太过分了,我认为必须有一种方法可以使用标准语言功能“轻松”地将二进制数据读入结构,而无需使用任何不安全的东西。我也想稍后将它用于嵌入式平台,所以代码大小对我来说实际上很重要。 (下面的最小可重现示例将使用 std 库,因此我们都可以从高点开始。)

2。我试过以下...

首先,这是我用来向我的程序发送 UDP 数据包进行测试的 php 脚本。

<?php

$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$pack = pack('C*', 4, 3, 1, 0);

socket_sendto($sock, $pack, strlen($pack), 0, '127.0.0.1', 1337);
socket_close($sock);

super 简单,pack一些二进制文件并通过网络将其发送到我的程序。一切都是已知的唯一值,因此我们可以确保将信息读入结构中的正确位置。

#![allow(non_snake_case)]

use std::net::UdpSocket;
use std::mem::size_of;

#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
struct ISP_TINY {
Size: u8, // Always 4
Type: u8, // Always ISP_TINY = 3
ReqI: u8, // 0 Unless return of a request for information.
SubT: u8, // Sub Type from the TINY_ enumeration.
}

fn main() -> std::io::Result<()>
{
// Some output so that we know the program has actally started.
println!("Running ...");

// Here we bind to the UDP socket, but the question mark allows us to return early if there is an error and end the program then and there.
let socket = UdpSocket::bind("0.0.0.0:1337")?;

// We'll read into this buffer space, but it has to be as big as or bigger than the largest packet your program can receive, otherwise it will cut off the rest of the data.
let mut buf = [0; 256];
loop
{
// recv_from blocks, and will wait (in sleep) until we get a packet to our bound socket.
let (bytes, socketAddress) = socket.recv_from(&mut buf)?;

// Once we get a packet, read from our buffer upto the packet length in bytes.
let packet = &mut buf[..bytes];

// Check that it's of the size we understand and want.
if bytes != size_of::<ISP_TINY>()
{
println!("Got packet of size {} need packet of size {}", bytes, size_of::<ISP_TINY>());
// Here we implicitly discard a packet we don't like and contiune the loop.
continue;
}

// When we get a packet we want, we print it's contents, it's size and where it came from.
println!("Packet Recv {:#?} of size {} from {}", packet, bytes, socketAddress);
}
}

3。显示一些代码。

为了让 Rust 满意,我已经进行了大量的实现。在过去的 24 小时里,我想我已经完成了大约 10 种不同的设计。他们似乎都不满意我提出的解决方案。

这看起来不像是一个难题。我有数据,我可以切入它吗?对吧?

        let tiny = ISP_TINY {
Size: packet[0 .. 1],
Type: packet[1 .. 2],
ReqI: packet[2 .. 3],
SubT: packet[3 .. 4]
};

error[E0308]: mismatched types
--> src/main.rs:42:19
|
42 | Size: packet[0 .. 1],
| ^^^^^^^^^^^^^^ expected `u8`, found slice `[u8]`

error[E0308]: mismatched types
--> src/main.rs:43:19
|
43 | Type: packet[1 .. 2],
| ^^^^^^^^^^^^^^ expected `u8`, found slice `[u8]`

error[E0308]: mismatched types
--> src/main.rs:44:19
|
44 | ReqI: packet[2 .. 3],
| ^^^^^^^^^^^^^^ expected `u8`, found slice `[u8]`

error[E0308]: mismatched types
--> src/main.rs:45:19
|
45 | SubT: packet[3 .. 4]
| ^^^^^^^^^^^^^^ expected `u8`, found slice `[u8]`

error: aborting due to 4 previous errors

所以我对自己说,也许我需要创建一个实现......

impl ISP_TINY
{
fn from(&self, packet: &[u8])
{
self.Size: packet[0 .. 1],
self.Type: packet[1 .. 2],
self.ReqI: packet[2 .. 3],
self.SubT: packet[3 .. 4]
}
}

它也不喜欢那样。

error: expected one of `!`, `(`, `::`, `;`, `<`, or `}`, found `[`
--> src/main.rs:19:26
|
19 | self.Size: packet[0 .. 1],
| - ^ expected one of `!`, `(`, `::`, `;`, `<`, or `}`
| |
| tried to parse a type due to this

error: aborting due to previous error

这是我认为合理的 10 个解决方案中的两个。但它们不起作用,我不确定如何在 Rust 语言中解决这个问题。如何将数据包中的原始二进制数据读取到结构中!?

最佳答案

只需按整数索引即可获得单个字节,例如packet[0] 而不是 packet[0..1]。这将为您提供一个 u8 而不是长度为 1 的切片。

用于将字节数组转换为更大的整数,例如u16i64等,可以使用from_le_bytes等函数、from_be_bytesfrom_ne_bytes 在 native 整数上定义。

关于rust - 将数据包读入 Rust 中的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61280818/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com