오늘은 Rust를 이용한 다중 클라이언트 채널형 채팅 프로그램을 구현해 보았다.
server.rs
use std::io::{self, ErrorKind, Read, Write};
use std::net::TcpListener;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
const MSG_SIZE: usize = 100;
fn main() {
println!("[Server]");
println!("\nEnter server ip");
let mut ip = String::new();
io::stdin().read_line(&mut ip).expect("Reading from stdin failed");
let server_ip = ip.trim().to_string();
println!("\nEnter server port");
let mut port = String::new();
io::stdin().read_line(&mut port).expect("Reading from stdin failed");
let server_port = port.trim().to_string();
let server_address = format!("{}{}{}", &server_ip, &String::from(":"), &server_port);
let server = TcpListener::bind(server_address).expect("Lister failed to bind");
server.set_nonblocking(true).expect("failed to initialize non blocking listener");
println!("\nWaiting for client connection..");
let mut clients = vec![];
let (tx, rx) = mpsc::channel::<String>();
loop {
if let Ok((mut socket, addr)) = server.accept() {
println!("client {} connected", addr);
let tx = tx.clone();
clients.push(socket.try_clone().expect("failed to clone client"));
let msg = format!("※ [{}]님이 입장하셨습니다. ※",addr);
tx.send(msg).expect("failed to send message to rx");
thread::spawn(move || loop {
let mut buff = vec![0; MSG_SIZE];
match socket.read_exact(&mut buff) {
Ok(_) => {
let msg = buff.into_iter().take_while(|&x| x != 0).collect::<Vec<_>>();
let msg = String::from_utf8(msg).expect("invalid utf8 message");
println!("[{}]{}", addr, msg);
let msg = format!("{}{}{}{}", &String::from("["), addr, &String::from("]"), &msg);
tx.send(msg).expect("failed to send message to rx");
},
Err(ref err) if err.kind() == ErrorKind::WouldBlock => (),
Err(_) => {
println!("Closing connection with [{}]", addr);
let msg = format!("※ [{}]님이 퇴장하셨습니다. ※",addr);
tx.send(msg).expect("failed to send message to rx");
break;
}
}
sleep();
});
}
if let Ok(msg) = rx.try_recv() {
clients = clients.into_iter().filter_map(|mut client| {
let mut buff = msg.clone().into_bytes();
buff.resize(MSG_SIZE, 0);
client.write_all(&buff).map(|_| client).ok()
})
.collect::<Vec<_>>();
}
sleep();
}
}
fn sleep() {
thread::sleep(Duration::from_millis(100));
}
client.rs
use std::io::{self, ErrorKind, Read, Write};
use std::net::TcpStream;
use std::sync::mpsc::{self, TryRecvError};
use std::thread;
use std::time::Duration;
const MSG_SIZE: usize = 100;
fn main() {
println!("[Client]");
println!("\nEnter server server_address");
let mut address = String::new();
io::stdin().read_line(&mut address).expect("Reading from stdin failed");
let server_address = address.trim().to_string();
let mut client = TcpStream::connect(server_address).expect("stream failed to connect");
client.set_nonblocking(true).expect("fialed to initialize non-blocking");
let (tx, rx) = mpsc::channel::<String>();
thread::spawn(move || loop {
// Read message:
let mut buff = vec![0; MSG_SIZE];
match client.read_exact(&mut buff) {
Ok(_) => {
let msg_byte_vec = buff.into_iter().take_while(|&x| x != 0).collect::<Vec<_>>();
let msg = String::from_utf8(msg_byte_vec).expect("invalid utf8 message");
println!("---------------------------------------------------------");
println!("{}", msg);
println!("---------------------------------------------------------");
},
Err(ref err) if err.kind() == ErrorKind::WouldBlock => (),
Err(_) => {
println!("connection with server was served");
break;
}
}
// Receive message from channel and Write message to the server
match rx.try_recv() {
Ok(msg) => {
let mut buff = msg.clone().into_bytes();
buff.resize(MSG_SIZE, 0);
client.write_all(&buff).expect("writing to socket failed");
},
Err(TryRecvError::Empty) => (),
Err(TryRecvError::Disconnected) => break
}
thread::sleep(Duration::from_millis(100));
});
println!("\nwhat is your name?");
let mut name_buff = String::new();
io::stdin().read_line(&mut name_buff).expect("Reading from stdin failed");
let name = name_buff.trim().to_string();
println!("\nPlease enter a message to send");
loop {
let mut buff = String::new();
io::stdin().read_line(&mut buff).expect("Reading from stdin failed");
let msg = format!("{}{}{:?}{}", &name, &String::from("님이 "), &buff.trim().to_string(), &String::from("을(를) 입력하셨습니다."));
if tx.send(msg).is_err() { break }
}
}
실행 화면
소스 코드 링크
https://github.com/levhyun/Rust_Chat
'Rust' 카테고리의 다른 글
Rust Socket Programming - Chapter 1 (0) | 2023.01.18 |
---|