Last active
September 8, 2023 08:02
-
-
Save ssrlive/45aaea6e80c32a1f31260bb1264896fb to your computer and use it in GitHub Desktop.
Mio demo with rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // [dependencies] | |
| // mio = { version = "0.8", features = ["net", "os-ext", "os-poll"] } | |
| use mio::{ | |
| event::Event, | |
| net::{TcpListener, TcpStream}, | |
| Events, Interest, Poll, Token, | |
| }; | |
| use std::{cell::RefCell, collections::HashMap, io::Read, net::SocketAddr, rc::Rc}; | |
| const SERVER: Token = Token(0); | |
| struct MyServer { | |
| listener: TcpListener, | |
| connections: HashMap<Token, TcpStream>, | |
| event_loop: Rc<RefCell<Poll>>, | |
| last_token: usize, | |
| } | |
| #[derive(Debug)] | |
| pub struct SErr(pub &'static str); | |
| impl std::fmt::Display for SErr { | |
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
| std::fmt::Display::fmt(self.0, f) | |
| } | |
| } | |
| impl std::error::Error for SErr {} | |
| impl MyServer { | |
| fn new(listener: TcpListener, event_loop: Rc<RefCell<Poll>>) -> MyServer { | |
| MyServer { | |
| listener, | |
| connections: HashMap::new(), | |
| event_loop, | |
| last_token: SERVER.0, | |
| } | |
| } | |
| fn new_token(&mut self) -> Token { | |
| self.last_token += 1; | |
| Token(self.last_token) | |
| } | |
| fn handle_event(&mut self, event: &Event) -> Result<(), Box<dyn std::error::Error>> { | |
| match event.token() { | |
| SERVER => { | |
| // 有新連接進來 | |
| loop { | |
| match self.listener.accept() { | |
| Ok((mut stream, _)) => { | |
| let token = self.new_token(); | |
| println!("New connection from: {}", stream.peer_addr()?); | |
| self.event_loop | |
| .borrow_mut() | |
| .registry() | |
| .register(&mut stream, token, Interest::READABLE)?; | |
| self.connections.insert(token, stream); | |
| } | |
| Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => return Ok(()), | |
| Err(e) => return Err(e.into()), | |
| } | |
| } | |
| } | |
| token => { | |
| // 有數據可讀 | |
| let mut buffer = [0; 1024]; | |
| loop { | |
| match self.connections.get_mut(&token).ok_or(SErr("error"))?.read(&mut buffer) { | |
| Ok(0) => { | |
| // 客戶端斷開連接 | |
| println!("Connection closed: {:?}", self.connections[&token].peer_addr()?); | |
| let mut stream = self.connections.remove(&token).ok_or(SErr("Connection not found"))?; | |
| self.event_loop.borrow_mut().registry().deregister(&mut stream)?; | |
| return Ok(()); | |
| } | |
| Ok(n) => { | |
| // 輸出收到的數據 | |
| let data = String::from_utf8_lossy(&buffer[..n]); | |
| println!("Received data from {}: {}", self.connections[&token].peer_addr()?, data); | |
| } | |
| Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => return Ok(()), | |
| Err(e) => return Err(e.into()), | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| fn main() -> Result<(), Box<dyn std::error::Error>> { | |
| // 建立事件循環 | |
| let event_loop = Rc::new(RefCell::new(Poll::new()?)); | |
| // 建立 TCP 監聽器 | |
| let address = "127.0.0.1:8080".parse::<SocketAddr>()?; | |
| let mut listener = TcpListener::bind(address)?; | |
| event_loop | |
| .borrow_mut() | |
| .registry() | |
| .register(&mut listener, SERVER, Interest::READABLE)?; | |
| let mut my_server = MyServer::new(listener, event_loop.clone()); | |
| println!("Server listening on {}", address); | |
| let mut events = Events::with_capacity(1024); | |
| loop { | |
| if let Err(err) = event_loop.borrow_mut().poll(&mut events, None) { | |
| if err.kind() == std::io::ErrorKind::Interrupted { | |
| continue; | |
| } | |
| return Err(err.into()); | |
| } | |
| println!("new event"); | |
| for event in &events { | |
| my_server.handle_event(event)?; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment