Compare commits
8 Commits
0d06438230
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d033c4c2c3 | ||
|
|
520db4fe58 | ||
|
|
bdecb76824 | ||
|
|
8ff5112352 | ||
|
|
57b35902ae | ||
|
|
a04e3d3299 | ||
|
|
4110207303 | ||
|
|
4110778123 |
@@ -1,3 +1,7 @@
|
|||||||
# rumes
|
# rumes
|
||||||
|
|
||||||
A TCP based P2P mesenging CLI Application
|
A TCP based P2P mesenging CLI Application
|
||||||
|
|
||||||
|
> its not P2P yet but i am working on it.
|
||||||
|
|
||||||
|
Don't take this Project seriously, i am just using it to learn TCP sockets and the Tokio librery
|
||||||
81
src/main.rs
81
src/main.rs
@@ -1,13 +1,15 @@
|
|||||||
use tokio::net::{TcpListener, TcpStream};
|
|
||||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||||
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
// Parse command-line arguments
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if args.len() != 3 {
|
if args.len() != 3 {
|
||||||
println!("Usage: {} [server|client] [addr:port]", args[0]);
|
println!("Usage: {} [server|client] [addr:port]", args[0]);
|
||||||
@@ -27,73 +29,92 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn start_server(addr: &str) -> Result<(), Box<dyn Error>> {
|
async fn start_server(addr: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
// Start the TCP listener
|
||||||
let listener = TcpListener::bind(addr).await?;
|
let listener = TcpListener::bind(addr).await?;
|
||||||
|
|
||||||
println!("Server listening on {}", addr);
|
println!("Server listening on {}", addr);
|
||||||
|
|
||||||
|
// Shared data for client connections
|
||||||
let clients: Arc<Mutex<HashMap<SocketAddr, String>>> = Arc::new(Mutex::new(HashMap::new()));
|
let clients: Arc<Mutex<HashMap<SocketAddr, String>>> = Arc::new(Mutex::new(HashMap::new()));
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
// Accept a new client connection
|
||||||
let (mut socket, client_addr) = listener.accept().await?;
|
let (mut socket, client_addr) = listener.accept().await?;
|
||||||
|
|
||||||
|
// Read username from the client
|
||||||
let mut buf = vec![0; 1024];
|
let mut buf = vec![0; 1024];
|
||||||
socket.read(&mut buf).await?;
|
let n = socket.read(&mut buf).await?;
|
||||||
|
let username = String::from_utf8_lossy(&buf[..n]).trim().to_string();
|
||||||
let username = String::from_utf8(buf.clone()).unwrap();
|
|
||||||
|
|
||||||
println!("Accepted connection from {}", client_addr);
|
println!("Accepted connection from {}", client_addr);
|
||||||
|
|
||||||
let clients_shared = Arc::clone(&clients);
|
let clients_shared = Arc::clone(&clients);
|
||||||
|
|
||||||
clients_shared.lock().unwrap().insert(client_addr, username);
|
// Insert client into the shared HashMap
|
||||||
|
clients_shared.lock().await.insert(client_addr, username.clone());
|
||||||
|
|
||||||
|
// Clone the HashMap and release the lock
|
||||||
|
let clients_map = clients_shared.lock().await.clone();
|
||||||
|
|
||||||
|
// Spawn a new task for each client connection
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut buf = vec![0; 1024];
|
let mut buf = vec![0; 1024];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let n = match socket.read(&mut buf).await {
|
let n = match socket.read(&mut buf).await {
|
||||||
Ok(n) if n == 0 => {
|
Ok(n) if n == 0 => {
|
||||||
let username = clients_shared.lock().unwrap().remove(&client_addr).unwrap_or("Unknown".to_string());
|
// Client disconnected
|
||||||
|
let username = clients_shared.lock().await.remove(&client_addr).unwrap_or("Unknown".to_string());
|
||||||
println!("Client {} ({}) disconnected!", username, client_addr);
|
println!("Client {} ({}) disconnected!", username, client_addr);
|
||||||
return;
|
return;
|
||||||
},
|
}
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("failed to read from socket; err = {:?}", e);
|
eprintln!("Failed to read from socket; err = {:?}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let username = clients_shared.lock().unwrap().get(&client_addr).unwrap_or(&"Unknown".to_string()).clone();
|
let username = clients_map.get(&client_addr).unwrap_or(&"Unknown".to_string()).clone();
|
||||||
|
|
||||||
println!("Received message from {} ({}): {}",
|
let message = String::from_utf8_lossy(&buf[..n]).to_string();
|
||||||
username,
|
println!(
|
||||||
|
"Received message from ({})\n{}: {}",
|
||||||
client_addr,
|
client_addr,
|
||||||
String::from_utf8_lossy(&buf[..n]));
|
username,
|
||||||
|
message
|
||||||
if let Err(e) = socket.write_all(&buf[0..n]).await {
|
);
|
||||||
eprintln!("failed to write to socket; err = {:?}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_client(addr: &str) -> Result<(), Box<dyn Error>> {
|
async fn start_client(addr: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
// Connect to the server
|
||||||
let mut stream = TcpStream::connect(addr).await?;
|
let mut stream = TcpStream::connect(addr).await?;
|
||||||
|
|
||||||
println!("Enter a username: ");
|
println!("Enter a username: ");
|
||||||
let mut username = String::new();
|
let mut username = String::new();
|
||||||
std::io::stdin().read_line(&mut username)?;
|
let mut reader = BufReader::new(tokio::io::stdin());
|
||||||
|
reader.read_line(&mut username).await?;
|
||||||
stream.write_all(username.as_bytes()).await?;
|
|
||||||
|
// Send username to the server
|
||||||
|
stream.write_all(username.trim().as_bytes()).await?;
|
||||||
|
|
||||||
println!("Connected to server at {}", addr);
|
println!("Connected to server at {}", addr);
|
||||||
let mut input = String::new();
|
|
||||||
loop {
|
loop {
|
||||||
std::io::stdin().read_line(&mut input)?;
|
let mut input = String::new();
|
||||||
stream.write_all(input.as_bytes()).await?;
|
reader.read_line(&mut input).await?;
|
||||||
input.clear();
|
|
||||||
|
let trimmed_input = input.trim();
|
||||||
|
|
||||||
|
if trimmed_input.is_empty() {
|
||||||
|
println!("Empty message. Please enter a non-empty message.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.write_all(trimmed_input.as_bytes()).await?;
|
||||||
|
|
||||||
|
// Print sent message
|
||||||
|
println!("Sent message from {}: {}", username.trim(), trimmed_input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user