使用通道在线程之间传递Rust pnet数据包
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用通道在线程之间传递Rust pnet数据包相关的知识,希望对你有一定的参考价值。
我正在研究一个简单的Rust程序,它读取和解析网络数据包。为了读取网络数据包我正在使用pnet libary。因为解析可能需要一些时间,我使用两个单独的线程来读取和解析数据包。
我现在的想法是通过消息传递(使用mpsc::channel()
)将读取包从第一个线程传递到第二个线程。这是我基于the example given in the pnet doc编写的代码的简化版本:
extern crate pnet;
use std::sync::mpsc;
use std::thread;
use pnet::datalink;
use pnet::datalink::Channel::Ethernet;
fn main() {
let (sender, receiver) = mpsc::channel();
thread::spawn(move || {
for packet in receiver.recv() {
println!("{:?}", packet)
}
});
let interface = datalink::interfaces().into_iter()
.find(|interface| interface.name == "enp5s0")
.unwrap();
let (_, mut package_receiver) =
match datalink::channel(&interface, Default::default()) {
Ok(Ethernet(tx, rx)) => (tx, rx),
_ => panic!()
};
loop {
match package_receiver.next() {
Ok(packet) => {
// sender.send("foo"); // this works fine
sender.send(packet);
}
_ => panic!()
}
}
}
这适用于通过通道发送基元类型或字符串,但不适用于网络数据包。当我尝试通过通道将数据包发送到解析器线程时,我得到以下编译器错误:
error[E0597]: `*package_receiver` does not live long enough
--> src/main.rs:28:15
|
28 | match package_receiver.next() {
| ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
36 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
我是Rust的新手,非常感谢他们的帮助!
packet
是&[u8]
类型,有一些生命的'a
也与package_receiver
调用中next()
的参考相同。生命周期的next()
定义如下所示:
fn next(&'a mut self) -> Result<&'a [u8]>
你send
&[u8]
线程。但是线程可以比你发送给它的引用更长,导致悬空引用。结果编译器抱怨他们需要'static
lifetime."foo"
工作,因为它是&'static str
。
一种方法是获取数据的所有权,然后将其作为值发送到另一个线程。
Ok(packet) => {
// sender.send("foo"); // this works fine
sender.send(packet.to_owned());
}
您还可以查看使用crossbeam的作用域线程
package_receiver.next()调用定义为:
pub trait DataLinkReceiver: Send {
fn next(&mut self) -> Result<&[u8]>;
}
并且mspc :: Sender将send定义为:
pub fn send(&self, t: T) -> Result<(), SendError<T>>
所以package_receiver.next()返回一个结果,该结果包含对一个字节片段的引用,&[u8]。所以当你再调用sender.send(包)时;那就是说你想把引用发送到另一个线程。但是,package_receiver.next()的匹配范围不保证引用的寿命长于范围的结尾。因此,无法保证其他线程在访问该数据时仍然有效。
str工作,因为它是一个静态生命周期字符串。无论什么线程读取它,该内存总是有效读取。
如果您将通话更改为:
sender.send(Vec::from(packet))
这将创建一个Vec变量,将数据包切片复制到新内存中,然后将该变量的所有权传递给另一个线程。这可以保证其他接收线程始终可以清楚地访问该数据。因为明确地传递了所有权,所以编译器知道接收线程中的代码,其中接收的Vec变量的生命周期结束。
关于使用.send()的结果也会有一些杂项错误,可以通过以下方式处理:
if sender.send(Vec::from(packet)).is_err() {
println!("Send error");
}
以上是关于使用通道在线程之间传递Rust pnet数据包的主要内容,如果未能解决你的问题,请参考以下文章