一个尚未完成,基于Rust实现的TCP内网CMD文字聊天Demo

446 阅读2分钟

这是一个简易的聊天程序demo,有三个部分组成,服务端,客户端,显示端

服务端,接受任意客户端和显示端的连接,并将每条来自某个客户端的消息广播给所有已经建立连接的客户端

客户端,一个只负责发送消息的程序

显示端,由于cmd输入文本会影响服务端 消息的正常显示,所以单独切分出一个客户端,只负责接收显示消息

简单说下怎么用。先在任意电脑上启动服务端,然后任意电脑上的客户端、显示端可以输入服务端的内网IP地址去建立连接

现在内网环境下的服务端端口是写死的,可以调整之后,出现一个电脑上存在多个服务端

目前存在的问题如下:客户端关掉窗口,还没写正常的shutdown关闭,服务端不会知道,所以clients会越来越大

效果图如下

image.png

image.png

服务端代码:

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let ip_address = local_ip_address::local_ip().expect("");
    let tcp_listener = TcpListener::bind(ip_address.to_string() + ":7777").expect("");
    let clients = Arc::new(Mutex::new(Vec::new()));
    for stream in tcp_listener.incoming() {
        let clients_clone = Arc::clone(&clients);
        let mut stream = stream.unwrap();
        let peer_addr = stream.peer_addr().expect("");
        clients_clone.lock().unwrap().push(stream.try_clone().unwrap());
        println!("客户端{:?}建立连接,当前连接的客户端为 {}", peer_addr, clients_clone.lock().unwrap().len());
        let clients_clone = Arc::clone(&clients);
        thread::spawn(move || {
            loop {
                let mut buf = [0; 1024];
                match stream.read(&mut buf) {
                    Ok(0) => {
                        clients_clone.lock().unwrap().retain(|c| c.peer_addr().unwrap() != peer_addr);
                        println!("客户端{}关闭连接,剩余连接客户端为 {}", peer_addr, clients_clone.lock().unwrap().len());
                        break;
                    }
                    Ok(n) => {
                        let my_text = String::from_utf8_lossy(&buf[0..n]).to_string();
                        let mut clients = clients_clone.lock().unwrap();
                        for client in clients.iter_mut() {
                            let client_addr = client.peer_addr().expect("");
                            let text = format!("{} ---> {}", peer_addr, my_text);
                            if let Err(e) = client.write_all(text.as_bytes()) {
                                println!("客户端{}写入数据失败: {:?}", client_addr, e);
                            }
                        }
                    }
                    Err(e) => {
                        println!("客户端{}读取数据失败: {:?}", peer_addr, e);
                        break;
                    }
                }
            }
        });
    }
}

客户端代码:

use std::io::{Read, stdin, Write};
use std::net::TcpStream;

fn main() {
    println!("请输入目标连接的IP地址");
    let mut string = String::new();
    stdin().read_line(&mut string).expect("");
    let mut tcp_stream = TcpStream::connect(string.trim().to_string() + ":7777").expect("");
    println!("成功建立与服务器的连接");
    loop {
        let mut string = String::new();
        stdin().read_line(&mut string).expect("");
        tcp_stream.write(string.as_bytes()).expect("");
    }
}

显示端代码:

use std::io::{Read, stdin};
use std::net::TcpStream;

fn main() {
    println!("请输入目标连接的IP地址");
    let mut string = String::new();
    stdin().read_line(&mut string).expect("");
    let mut tcp_stream = TcpStream::connect(string.trim().to_string() + ":7777").expect("");
    println!("建立连接");
    loop {
        let mut buf = [0; 1024];
        tcp_stream.read(&mut buf).expect("");
        println!("{}", String::from_utf8_lossy(&buf).replace("\n", "").replace("\0", "").replace("\r", ""));
    }
}