You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust是否有类似Node.js创建持久TCP服务器的等效功能?

Rust 实现类似 Node.js 的 TCP 服务器

问题描述

我希望在 Rust 中实现与 Node.js 如下代码类似的 TCP 服务器功能:

const server = createServer(socket => {
  socket.on("data", (data) => {
  });
  socket.on("close", () => log("closed"));
});
server.on("error", err => { throw err; });
server.on("close", () => log("shutdown"));

我尝试使用了 Rust 的 TcpListener,但发现它似乎不具备我需要的全部功能,且连接无法保持持久,无法获取客户端的握手数据包。请问:

  • Rust 的 TcpListener 会自动关闭连接吗?
  • Rust 中是否有我不知道的持久化 TCP 工具?

解答

关于 TcpListener 是否自动关闭连接

TcpListener 本身不会自动关闭连接。连接关闭的常见原因包括:

  • 处理连接的代码执行完毕,TcpStream 因 Rust 所有权机制被销毁,触发 TCP 连接关闭流程
  • 客户端主动断开连接
  • 网络异常导致连接中断

你遇到的连接无法持久,大概率是因为处理单个连接的函数执行完成后,TcpStream 被自动释放,进而关闭了连接。要保持连接,需要在处理函数中持续监听该 TcpStream 的数据。

用标准库实现持久化 TCP 服务器

TcpListener 完全可以满足需求,不需要额外工具。以下是对应功能的示例代码:

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use ctrlc;

fn handle_client(mut stream: TcpStream, server_running: Arc<AtomicBool>) {
    let mut buffer = [0; 1024];
    // 循环读取数据,维持连接
    while server_running.load(Ordering::Relaxed) {
        match stream.read(&mut buffer) {
            Ok(0) => {
                // 读取0字节代表客户端主动关闭连接
                println!("closed");
                break;
            }
            Ok(n) => {
                // 这里处理收到的数据,示例仅打印
                println!("Received {} bytes: {:?}", n, &buffer[..n]);
                // 如需回复客户端,可调用 stream.write_all(&buffer[..n])
            }
            Err(e) => {
                eprintln!("读取数据出错: {}", e);
                break;
            }
        }
    }
}

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").expect("绑定地址失败");
    let server_running = Arc::new(AtomicBool::new(true));
    let running_clone = server_running.clone();

    // 处理Ctrl+C关闭信号
    ctrlc::set_handler(move || {
        running_clone.store(false, Ordering::Relaxed);
        println!("shutdown");
        std::process::exit(0);
    }).expect("设置信号处理器失败");

    println!("服务器监听 127.0.0.1:8080");

    // 循环接受新连接,每个连接启动独立线程处理
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                let running = server_running.clone();
                thread::spawn(move || {
                    handle_client(stream, running);
                });
            }
            Err(e) => {
                eprintln!("接受连接出错: {}", e);
                if !server_running.load(Ordering::Relaxed) {
                    break;
                }
            }
        }
    }
}

代码关键点说明

  • 通过 listener.incoming() 循环接受新连接,每个连接启动单独线程处理,避免阻塞主线程
  • handle_client 函数中用循环持续读取 TcpStream 数据,只要循环不终止,TcpStream 就不会被销毁,连接得以保持
  • 用 AtomicBool 标记服务器运行状态,处理关闭信号时通知所有连接线程退出
  • 读取到0字节时,判定客户端主动关闭连接,退出循环释放 TcpStream

关于握手数据包

如果是指TCP三次握手后的应用层握手,TcpListener 接受连接后,TcpStream 已经完成TCP三次握手,你可以直接在 handle_client 函数开头读取应用层的握手数据包即可。


内容的提问来源于stack exchange,提问作者May

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 13:25:15