Skip to content

Instantly share code, notes, and snippets.

@tamamu
Created August 24, 2020 11:12
Show Gist options
  • Save tamamu/f1bbd4d740079a84e624b9648a9d3e08 to your computer and use it in GitHub Desktop.
Save tamamu/f1bbd4d740079a84e624b9648a9d3e08 to your computer and use it in GitHub Desktop.
Rustでチャットサーバ(TCP)を書く
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