sockets - Rust 中 TcpListener 和 TcpAcceptor 的职责

标签 sockets std rust

我可以在 Rust 中很容易地创建 TcpListener 和 TcpAcceptor,但我不太明白它们的作用。听众似乎并没有真正倾听,只是接受者的一个设置结构。

let tcp_listener = TcpListener::bind(addr);
let mut acceptor = tcp_listener.listen();
drop(acceptor);

让我感到困惑的一件事是挂断电话。我不知道 drop 在哪里定义,我搜索了一些标准库,但我只能找到它作为特征方法。

另外,为什么丢弃接受器会停止监听?那不应该只是停止接受吗?你肯定想放弃听众。为什么甚至有一个 TcpListener,因为接受者似乎无所不能?

最佳答案

简而言之,在 BSD 套接字框架中,服务器的启动频率如下:

  • 使用 socket() 系统调用创建主服务器套接字;
  • 使用 bind() 系统调用将主套接字绑定(bind)到特定地址/端口;
  • 使用listen() 系统调用“启动”主套接字;从这一刻起,直到主套接字关闭,它将接管它绑定(bind)的端口并监听传入的连接;
  • 当主套接字处于监听状态时,可以调用accept();此调用将阻塞,直到某个客户端连接,然后它将返回一个表示与该客户端的连接的新套接字;与此客户端的所有通信都通过此套接字;当交互结束时,应该关闭这个套接字。

Rust 中 TCP 栈使用的主要方法的命名遵循标准的 BSD 套接字命名,但是 Rust API 更加抽象,因此隐藏了一些底层概念。

TcpListener::bind() 创建一个新的主套接字(socket() 系统调用)并将其绑定(bind)到提供的地址(bind() 系统调用)。它返回一个对象 TcpListener,该对象将主套接字封装为“已创建,但未激活”状态。

TcpListener 提供了一个名为 TcpListener::listen() 的方法,它包装了 listen() 系统调用并“激活”服务器套接字。它返回一个新对象 TcpAcceptor,它为接受传入连接提供了方便的接口(interface)。它代表处于“已创建和事件”状态的主套接字。

TcpAcceptor 依次有几个方法(TcpAcceptor::incoming()TcpAcceptor::accept())包装 accept() 系统调用并阻止当前任务,直到某个客户端建立连接,这导致 TcpStream - 一个表示客户端套接字的对象。

当调用它们的析构函数 时,与所有套接字关联的所有操作系统资源都将被释放。 Rust 中的析构函数可以与任何自定义结构相关联。要将析构函数添加到您的结构中,您必须为其实现 Drop 特性。当此类结构的实例超出范围时调用析构函数,例如:

struct Test { value: int }

impl Drop for Test {
    fn drop(&mut self) {
        println!("Dropping Test: value is {}", self.value);
    }
}

fn main() {
    let test = Test { value: 10 };
    // main ends, `test` goes out of scope
}

此程序打印Dropping Test: value is 10

对于实现了 Drop 特性的结构来说,重要的是它们不可隐式复制。这意味着当此类结构的实例被传递给函数参数或分配给不同的变量时,它们会从它们的原始位置移出,也就是说,您不能再通过它们的原始变量使用它们。例如(使用上面的 Test 定义):

let test = Test { value: 10 };
let test2 = test;
println!("{}", test.value);  // error: use of moved value: `test`

drop() 函数定义在core::mem 模块中; here是它的文档。它的实现非常简单;它看起来像这样:

fn drop<T>(x: T) { }

它什么都不做!但是因为它按值接受它的参数,所以该参数被移动到 drop() 调用中。然后所述参数立即超出范围,因为函数返回。如果 T 有关联的析构函数,它将在这里运行。因此,drop() 本质上是一个“黑洞”:您放入其中的所有内容都会被销毁(除非它是隐式可复制的,也就是说)。该语言的一个很好的特性是这样的函数可以用普通的 Rust 编写,不需要任何魔法。

事实上,drop() 没有什么用处,因为所有析构函数总是在相应对象超出范围时运行。当需要一些具有可破坏资源的复杂逻辑时,它偶尔会有用,但这种情况很少发生。

关于sockets - Rust 中 TcpListener 和 TcpAcceptor 的职责,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24023795/

相关文章:

c++ - 有没有一种简单的方法可以从 C++ 中的路径获取文件名?

rust - 如何使用通用 VecDeque?

rust - 如何使用 rustc-env 标志指定环境变量?

rust - 如何从 Rust 进程内部重定向 stderr?

sockets - 在sails v0.11(客户端)中发出消息

Python套接字未接收消息

python - 在不使用外部库的情况下获取以太网适配器 IPv4 地址

C# TCP 服务器不可靠,丢弃过时的缓冲消息

c++ - 构造函数重载造成困惑

c++ - 使用 find_if() 函数