如何移动借用的内容以关闭连接
How to move borrowed content to close connection
以下代码应该接受 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 案例中,我想处理客户端挂断。在那种情况下,我想我需要将连接的所有权从我的处理程序转移到该方法,以便让它超出范围以关闭它。
不幸的是生锈不允许我移动连接:
error: cannot move out of borrowed content
据我了解,问题是 &self
是在 readable
方法中借用的,因此无法访问其字段。
如何访问连接? (避免上述错误。)
如何关闭该连接? (即转让所有权。)
我假设原始代码中的错误来自这一行:
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 编译器静态插入 drop 调用。
以下代码应该接受 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 案例中,我想处理客户端挂断。在那种情况下,我想我需要将连接的所有权从我的处理程序转移到该方法,以便让它超出范围以关闭它。
不幸的是生锈不允许我移动连接:
error: cannot move out of borrowed content
据我了解,问题是 &self
是在 readable
方法中借用的,因此无法访问其字段。
如何访问连接? (避免上述错误。)
如何关闭该连接? (即转让所有权。)
我假设原始代码中的错误来自这一行:
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 编译器静态插入 drop 调用。