2

下面的代码应该接受 tcp 连接,从中读取,并在挂断时关闭它们。

extern crate mio;
use mio::{EventLoop,Token,ReadHint};
use mio::tcp::{TcpListener, TcpStream};
use std::io::Read;

const L_CLIENT: Token = Token(0);
const C_CLIENT: Token = Token(1);

fn sa(port:u16) -> std::net::SocketAddr {
  let ipa : std::net::Ipv4Addr = std::net::Ipv4Addr::new(127,0,0,1);
  std::net::SocketAddr::V4(std::net::SocketAddrV4::new(ipa,port))
}

fn main(){
  let mut event_loop = EventLoop::new().unwrap();

  let lclient = TcpListener::bind(&sa(4000)).unwrap();
  event_loop.register(&lclient, L_CLIENT).unwrap();

  println!("running loop...");
  event_loop.run(&mut MyHandler{lclient:lclient,cclient:None}).unwrap();
  println!("done.");
}

struct MyHandler{
  lclient:TcpListener,
  cclient:Option<TcpStream>,
}

impl mio::Handler for MyHandler {
  type Timeout = ();
  type Message = ();

  fn readable(&mut self, event_loop: &mut EventLoop<Self>, token: Token, hint: ReadHint){
    match token {
      L_CLIENT => {
        let s=self.lclient.accept().unwrap().expect("no client??");
        match self.cclient{
          None => {event_loop.register(&s,C_CLIENT);self.cclient=Some(s);}
          Some(_) =>{println!("ignore second client");} // s should be closed as it goes out of scope
        }
      },
      C_CLIENT => {
        let mut client=self.cclient.expect("connection is gone"); // what's the problem here?
        if hint.is_hup() {
          event_loop.deregister(&client);
          self.cclient=None; // how to close connection? 
        } else  {
          let mut buf: [u8; 500] = [0; 500];
          let l=client.read(&mut buf).unwrap();
          println!("read {} bytes.",l);
        }
      },
      _ =>{println!("other Token");}
    }
  }
}

这几乎可以工作。在 C_CLIENT 情况下,我想处理客户端挂断。在那种情况下,我想我需要将连接的所有权从我的处理程序转移到方法,以便让它超出范围以关闭它。

不幸的是,rust 不允许我移动连接:

 error: cannot move out of borrowed content

据我了解,问题在于&self该方法是借用的readable,因此无法访问其字段。

如何访问连接?(避免上述错误。)

如何关闭该连接?(即转让所有权。)

4

1 回答 1

2

我假设原始代码中的错误来自这一行:

let mut client=self.cclient.expect("connection is gone");

这是不允许的,因为Option::expect它拥有其参数的所有权,但readable只有一个借用的引用。只有所有者才能将值移动到新所有者。

您可以使用Option:::take. 这不是移动原始选项,而是借用并改变它,将其更改为None并返回其原始值:

let client = self.cclient.take().expect("connection is gone");
// Now `client` is a TcpStream and `self.cclient` is None.

但是,根本没有必要移动该值。您已经有一个可变引用,因此您可以就地对其进行变异:

C_CLIENT => {
    if hint.is_hup() {
        event_loop.deregister(&self.cclient);
        self.cclient = None;
    } else  {
        let mut buf: [u8; 500] = [0; 500];
        let l = self.cclient.read(&mut buf).unwrap();
        println!("read {} bytes.",l);
    }
},

当您编写self.cclient = None;时,self.cclient 的旧值会立即被删除,从而关闭连接。在 Rust 中,当不再拥有一个值时,它就会被删除。当其所有者超出范围或重新分配其所有者时,可能会发生这种情况。当变量超出范围或被重新分配时,Rust 编译器会静态插入删除调用。

于 2015-06-11T01:00:11.957 回答