我正在尝试使用Rust进行torrent抓取。我遇到了这个问题:我可以在Wireshark中看到传入的包,但我的recv_from
调用总是返回Error("End of file")
。这是我的计划:
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use std::io::net::udp::UdpSocket;
use std::rand;
use std::io::MemWriter;
fn main() {
let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 35000 };
let mut socket = match UdpSocket::bind(addr) {
Ok(s) => s,
Err(e) => panic!("couldn't bind socket: {}", e),
};
let mut buf: Vec<u8> = Vec::with_capacity(1000);
let transaction_id: u32 = rand::random();
let mut req_data = MemWriter::with_capacity(16);
req_data.write_be_u64(0x41727101980).unwrap(); // connection_id, identifies the protocol.
req_data.write_be_u32(0).unwrap(); // action: connect
req_data.write_be_u32(transaction_id).unwrap();
println!("{}", socket.send_to(req_data.get_ref(), ("31.172.63.252", 80)));
match socket.recv_from(buf.as_mut_slice()) {
Ok((amt, src)) => {
println!("Got {} bytes from {}.", amt, src);
},
Err(err) => println!("Can't recv_from: {}", err)
}
}
输出始终为:
➜ udp-bug git:(master) ✗ cargo run
Compiling udp-bug v0.0.1 (file:///home/omer/rust/udp-bug)
Running `target/udp-bug`
Ok(())
Can't recv_from: end of file
但是,我可以看到Wireshark中的预期响应:
20235 3512.148636000 31.172.63.252 192.168.1.4 QUIC 60 CID: 0, Seq: 0
这个包有16个字节的有效载荷,正是我所期望的。
任何想法出了什么问题?
答案 0 :(得分:3)
我认为您的问题是您使用Vec::with_capacity()
作为可变切片。 Vec::with_capacity()
仅创建具有指定容量(自然)的向量,但其长度为零。因此,从矢量中取出的切片长度也将为零:
let v = Vec::with_capacity(128);
println!("{}", v.as_mut_slice().len()); // prints 0
切片无法增长,因此recv_from()
没有可写入的空间,并且因错误而失败。
这里基本上有两种选择。第一个是使用不安全的set_len()
方法:
let mut buf: Vec<u8> = Vec::with_capacity(1000);
unsafe { buf.set_len(1000); }
这样缓冲区将具有正确的长度,但其内容可能只是垃圾。但是,这对于这个用例来说并不是很重要,只要您只访问正确的字节数(使用recv_from()
返回的信息)。
然而,还有更好的方法。您可以使用堆栈分配的固定大小数组:
let mut buf = [0u8, ..1000];
// ...
match socket.recv_from(buf.as_mut_slice()) {
// ...
}
同样适用于您的req_data
:您可以使用静态大小的数组和BufWriter
:
let transaction_id: u32 = rand::random();
let mut req_data_buf = [0u8, ..16];
let mut req_data = BufWriter::new(req_data_buf);
req_data.write_be_u64(0x41727101980).unwrap(); // connection_id, identifies the protocol.
req_data.write_be_u32(0).unwrap(); // action: connect
req_data.write_be_u32(transaction_id).unwrap();
println!("{}", socket.send_to(req_data_buf, ("31.172.63.252", 80)));
这只适用于固定大小的缓冲区。如果您不知道缓冲区的大小,则仍需要Vec
。