Categories
rust

Rust 异步编程

第一步 安装tokio库

cargo add tokio --features full
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 绑定到本地地址的8080端口
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    println!("服务器正在监听 127.0.0.1:8080");

    loop {
        // 等待新的连接
        let (socket, addr) = listener.accept().await?;
        println!("接收到来自 {} 的新连接", addr);

        // 为每个连接生成一个新任务
        tokio::spawn(async move {
            if let Err(e) = handle_connection(socket).await {
                println!("处理连接时出错: {}", e);
            }
        });
    }
}

async fn handle_connection(mut socket: TcpStream) -> Result<(), Box<dyn Error>> {
    // 创建一个缓冲区来存储数据
    let mut buf = [0; 1024];

    loop {
        // 读取数据
        let size = match socket.read(&mut buf).await {
            // 客户端关闭了连接
            Ok(size) if size == 0 => return Ok(()),
            Ok(size) => size,
            Err(e) => {
                return Err(e.into());
            }
        };

        let data = &buf[..size];
        let received = String::from_utf8_lossy(data);
        println!("Received data: {}", received);
        // 检查是否是telnet的断开命令(IAC IP)
        if size >= 3 && buf[0] == 255 && buf[1] == 244 {
            println!("Detected telnet disconnect command (IAC IP)");
             //显示关闭连接并且传播异常
            socket.shutdown().await?;
            //这个也能退出事件循环 关闭连接
            return Ok(());
        }
        
        // 检查普通ASCII的CTRL+C (3)
        if buf[..size].contains(&3) {
            println!("Detected CTRL+C, closing connection");
            //显示关闭连接并且传播异常
            socket.shutdown().await?;
            //这个也能退出事件循环 关闭连接
            return Ok(());
        }

        println!("接收到 {} 字节数据", size);

        // 将数据写回客户端
        if let Err(e) = socket.write_all(&buf[0..size]).await {
            return Err(e.into());
        }
    }
}
Categories
rust

Rust 网络编程

服务端代码:socket阻塞循环读

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

fn handle_client(mut stream: TcpStream) {
    let mut buffer = [0; 1024];

    loop {
        match stream.read(&mut buffer) {
            Ok(0) => {
                // 客户端关闭连接
                println!("Client disconnected");
                break;
            }
            Ok(size) => {
                // 读取到数据,回显给客户端
                let data = &buffer[..size];
                let received = String::from_utf8_lossy(data);
                println!("Received data: {}", received);
                // 检查是否是telnet的断开命令(IAC IP)
                if size >= 3 && buffer[0] == 255 && buffer[1] == 244 {
                    println!("Detected telnet disconnect command (IAC IP)");
                    if let Err(e) = stream.shutdown(std::net::Shutdown::Both) {
                        println!("Error shutting down stream: {}", e);
                    }
                    break;
                }
                
                // 检查普通ASCII的CTRL+C (3)
                if buffer[..size].contains(&3) {
                    println!("Detected CTRL+C, closing connection");
                    if let Err(e) = stream.shutdown(std::net::Shutdown::Both) {
                        println!("Error shutting down stream: {}", e);
                    }
                    break;
                }

                 if let Err(e) = stream.write_all(&buffer[..size]) {
                    println!("Error writing to stream: {}", e);
                    break;
                }
            }
            Err(e) => {
                // 发生错误,关闭连接
                println!("Error: {}", e);
                break;
            }
        }
    }
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:65432").unwrap();
    println!("Server listening on 127.0.0.1:65432");

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                // 为每个客户端连接创建一个新线程
                thread::spawn(move || {
                    handle_client(stream);
                });
            }
            Err(e) => {
                println!("Error accepting stream: {}", e);
                break;
            }
        }
    }

    // 注意:在实际应用中,应该优雅地关闭监听器,比如监听一个关闭信号。
    // 这里为了简化,直接退出主循环后程序将结束。
}

client 端代码

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

fn main() -> io::Result<()> {
    let mut stream = TcpStream::connect("127.0.0.1:65432")?;
    println!("Connected to server!");
    
    loop {
        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        
        if input.contains('\x03') { // CTRL+C
            println!("Sending CTRL+C to server");
            stream.write_all(input.as_bytes())?;
            break;
        }
        
        stream.write_all(input.as_bytes())?;
        
        let mut buffer = [0; 1024];
        let size = stream.read(&mut buffer)?;
        if size == 0 {
            println!("Server closed connection");
            break;
        }
        
        println!("Server echo: {}", String::from_utf8_lossy(&buffer[..size]));
    }
    
    Ok(())
}