Created
August 24, 2020 11:12
-
-
Save tamamu/f1bbd4d740079a84e624b9648a9d3e08 to your computer and use it in GitHub Desktop.
Rustでチャットサーバ(TCP)を書く
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
use std::io::prelude::*; | |
use std::net::{TcpListener, TcpStream}; | |
use std::{thread, time}; | |
use std::collections::HashMap; | |
use std::sync::{Arc, Mutex}; | |
const HOST: &'static str = "127.0.0.1:80"; | |
struct Server { | |
connections: HashMap<String, Arc<Mutex<TcpStream>>>, | |
} | |
impl Server { | |
fn new() -> Self { | |
Self { | |
connections: HashMap::new(), | |
} | |
} | |
fn broadcast(&mut self, sender_addr: &str, message: String) -> std::io::Result<()> { | |
let mut buf = format!("[{}] ", sender_addr); | |
buf.push_str(&message); | |
let bytes = buf.as_bytes(); | |
for (addr, stream) in self.connections.iter_mut() { | |
if *addr == sender_addr { continue; } | |
stream.lock().unwrap().write(bytes)?; | |
} | |
Ok(()) | |
} | |
fn add_connection(&mut self, addr: String, connection: Arc<Mutex<TcpStream>>) { | |
self.connections.insert(addr.clone(), connection); | |
self.broadcast(&addr, format!("enter the new client from {}\n", &addr)).unwrap(); | |
} | |
} | |
fn handle_client(server: Arc<Mutex<Server>>, stream: Arc<Mutex<TcpStream>>) { | |
loop { | |
thread::sleep(time::Duration::from_millis(150)); | |
{ | |
let mut buffer = [0; 1024]; | |
let addr = stream.lock().unwrap().peer_addr().unwrap().to_string(); | |
let result = stream.lock().unwrap().read(&mut buffer); | |
match result { | |
Ok(_) => { | |
let message = String::from_utf8_lossy(&buffer[..]).to_string(); | |
println!("[{}] {}", addr, message); | |
server.lock().unwrap().broadcast(&addr, message).unwrap(); | |
} | |
Err(_) => { | |
//eprintln!("[{}] <timeout>", addr); | |
} | |
} | |
} | |
} | |
} | |
fn main() -> std::io::Result<()> { | |
let server = Arc::new(Mutex::new(Server::new())); | |
let listener = TcpListener::bind(HOST)?; | |
for stream in listener.incoming() { | |
match stream { | |
Ok(s) => { | |
s.set_read_timeout(Some(time::Duration::from_millis(300))).expect("cannot set read_timeout"); | |
let addr = s.peer_addr().unwrap().to_string(); | |
let shared_s = Arc::new(Mutex::new(s)); | |
{ | |
server.lock().unwrap().add_connection(addr, shared_s.clone()); | |
} | |
let svr = server.clone(); | |
thread::spawn(move || { | |
handle_client(svr, shared_s.clone()); | |
}); | |
}, | |
Err(e) => { | |
eprintln!("{}", e); | |
} | |
} | |
} | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment