我可以在Rust中很容易地创建一个TcpListener和TcpAcceptor,但是我不太了解它们的作用。监听器似乎并没有真正监听,而仅仅是接收者的设置结构。

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

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

另外,为什么放弃接受者会停止收听?那不应该只是停止接受吗?当然,您想删除监听器。为什么甚至还有一个TcpListener,因为接受者似乎可以做所有事情?

最佳答案

简而言之,在BSD套接字框架中,这是服务器启动的通常方式:

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

  • 在Rust中,TCP堆栈使用的主要方法的命名遵循标准的BSD套接字命名,但是,Rust API更抽象,因此隐藏了一些底层概念。
    TcpListener::bind()创建一个新的主套接字(socket()系统调用)并将其绑定(bind)到提供的地址(bind()系统调用)。它返回一个对象TcpListener,该对象将主套接字封装为“已创建但未处于 Activity 状态”。
    TcpListener提供了一种称为TcpListener::listen()的方法,该方法包装了listen()系统调用并“激活”服务器套接字。它返回一个新对象TcpAcceptor,它提供了方便的接口(interface)来接受传入的连接。它表示处于“创建和 Activity ”状态的主套接字。
    TcpAcceptor依次具有几种方法(TcpAcceptor::incoming()TcpAcceptor::accept()),这些方法包装accept()系统调用并阻止当前任务,直到某些客户端建立连接导致TcpStream(代表客户端套接字的对象)为止。

    与所有套接字关联的所有OS资源在调用其析构函数时都将释放。 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/

    10-11 23:04
    查看更多