当前位置: 首页 > news >正文

【Rust TCP编程】Rust网络编程之TCP编程语法解析与应用实战

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Rust开发,Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:Rust语言通关之路
景天的主页:景天科技苑

在这里插入图片描述

文章目录

  • Rust TCP编程
    • 1. TCP协议基础
    • 2. Rust网络编程概览
    • 3. 创建TCP服务器
      • 3.1 基本服务器
      • 3.2 代码解析
      • 3.3 改进服务器
    • 4. 创建TCP客户端
      • 4.1 基本客户端
      • 4.2 代码解析
      • 4.3 改进客户端
    • 5. 基于tcp的大文件传输
    • 6. 性能优化技巧
      • 6.1 缓冲区管理

Rust TCP编程

Rust是一种系统编程语言,专注于安全、并发和性能。它提供了零成本抽象、内存安全和线程安全等特性,使其成为网络编程的理想选择。
本文将详细介绍如何在Rust中进行TCP网络编程,涵盖从基础概念到实际应用的各个方面。

1. TCP协议基础

TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在Rust中进行TCP编程前,我们需要了解一些基本概念:

  • 面向连接:通信双方必须先建立连接才能传输数据
  • 可靠性:TCP保证数据按序到达,无差错、不丢失、不重复
  • 全双工:连接双方可以同时发送和接收数据
  • 流量控制:防止发送方发送过快导致接收方来不及处理
  • 拥塞控制:防止网络过载
    TCP使用IP地址和端口号来标识通信端点,通常表示为IP:Port的形式。

2. Rust网络编程概览

Rust标准库提供了强大的网络编程支持,主要位于std::net模块中。对于TCP编程,我们需要关注以下几个关键类型:

  • TcpListener:用于监听TCP连接的服务器端组件
  • TcpStream:表示一个TCP连接的双向流
  • SocketAddr:表示IP地址和端口号的组合
    此外,Rust的异步网络编程通常使用tokio或async-std等异步运行时,但本文主要关注同步编程模型。

3. 创建TCP服务器

3.1 基本服务器

让我们从创建一个简单的TCP服务器开始,它监听本地端口8080并接受连接:

use std::net::{ TcpListener, TcpStream };
use std::io::{ Read, Write };//定义处理客户端连接的函数
fn handle_client(mut stream: TcpStream) {//读取客户端发送的数据,每次读取512字节let mut buffer = [0; 512];stream.read(&mut buffer).unwrap();//打印接收到的数据println!("Received: {}", String::from_utf8_lossy(&buffer[..]));//向客户端发送响应let response = b"HTTP/1.1 200 OK\r\n\r\nHello from server!";stream.write(response).unwrap();//刷新缓冲区,确保数据被发送stream.flush().unwrap();
}fn main() -> std::io::Result<()> {//绑定到指定地址和端口,创建TCP监听器let listener = TcpListener::bind("127.0.0.1:8080")?;println!("Server listening on port 8080");//循环处理客户端连接for stream in listener.incoming() {match stream {Ok(stream) => {handle_client(stream);}Err(e) => {println!("Connection failed: {}", e);}}}Ok(())
}

3.2 代码解析

TcpListener::bind()创建一个新的TCP监听器,绑定到指定的地址和端口
listener.incoming()返回一个迭代器,产生连接的TcpStream对象
handle_client函数处理每个连接:

  • 创建一个缓冲区来读取数据
  • 从流中读取数据并打印
  • 写回一个简单的HTTP响应

3.3 改进服务器

上面的服务器只能处理一个连接,让我们改进它以处理多个连接:

use std::net::{ TcpListener, TcpStream };
use std::io::{ Read, Write };
use std::thread;//定义处理客户端连接的函数
fn handle_client(mut stream: TcpStream) {//读取客户端发送的数据,每次读取512字节let mut buffer = [0; 512];//循环读取数据loop {let bytes_read = stream.read(&mut buffer).unwrap();if bytes_read == 0 {//如果客户端关闭连接,则退出循环break;}//打印接收到的数据println!("Received: {}", String::from_utf8_lossy(&buffer[..]));//向客户端发送响应let response = b"HTTP/1.1 200 OK\r\n\r\nHello from server!";stream.write(response).unwrap();//刷新缓冲区,确保数据被发送stream.flush().unwrap();}
}fn main() -> std::io::Result<()> {let listener = TcpListener::bind("127.0.0.1:8080")?;println!("Server listening on port 8080");//创建一个容器,用于存储线程句柄let mut handlers = Vec::new();//循环处理客户端连接for stream in listener.incoming() {match stream {Ok(stream) => {//为每个客户端连接创建一个新的线程let handler = thread::spawn(move || {handle_client(stream);});handlers.push(handler);}Err(e) => {println!("Connection failed: {}", e);}}}//等待所有线程结束for handler in handlers {handler.join().unwrap();}Ok(())
}

现在每个连接都在单独的线程中处理,服务器可以同时服务多个客户端。

4. 创建TCP客户端

4.1 基本客户端

让我们创建一个简单的TCP客户端来连接我们的服务器:

use std::net::TcpStream;
use std::io::{ Read, Write };fn main() -> std::io::Result<()> {//连接到服务器let mut stream = TcpStream::connect("127.0.0.1:8080")?;println!("Connected to server!");//向服务器发送数据let message = b"Hello from client!";stream.write(message)?;stream.flush()?;//读取服务器的响应let mut buffer = [0; 512];stream.read(&mut buffer)?;println!("Received: {}", String::from_utf8_lossy(&buffer[..]));Ok(())
}

4.2 代码解析

TcpStream::connect()尝试连接到指定的服务器地址
write()方法发送数据到服务器
read()方法从服务器读取响应数据

4.3 改进客户端

让我们改进客户端以发送多行文本并保持连接:

use std::net::{ TcpListener, TcpStream };
use std::io::{ Read, Write };
use std::thread;//定义处理客户端连接的函数
fn handle_client(mut stream: TcpStream) {//读取客户端发送的数据,每次读取512字节let mut buffer = [0; 512];stream.read(&mut buffer).unwrap();//打印接收到的数据println!("Received: {}", String::from_utf8_lossy(&buffer[..]));//向客户端发送响应let response = b"HTTP/1.1 200 OK\r\n\r\nHello from server!";stream.write(response).unwrap();//刷新缓冲区,确保数据被发送stream.flush().unwrap();
}fn main() -> std::io::Result<()> {let listener = TcpListener::bind("127.0.0.1:8080")?;println!("Server listening on port 8080");for stream in listener.incoming() {match stream {Ok(stream) => {//为每个客户端连接创建一个新的线程thread::spawn(|| {handle_client(stream);});}Err(e) => {println!("Connection failed: {}", e);}}}Ok(())
}

5. 基于tcp的大文件传输

我们仍使用标准库,并处理大文件(>1GB)时的流式传输。
u64 可支持 最大 16EB(远超文件系统限制)。
流式处理确保低内存使用

  • 高效:避免一次性读入大文件,占用大量内存。
  • 稳定:处理断点、部分传输、TCP粘包。
  • 可靠:尽量传完全部字节,确保不丢包。

服务器:接收大文件(server.rs)

use std::net::{ TcpListener, TcpStream };
use std::io::{ Read, Write };
use std::fs::File;
use std::thread;
use std::path::PathBuf;fn handle_client(mut stream: TcpStream) -> std::io::Result<()> {let mut len_buf = [0; 2];stream.read_exact(&mut len_buf)?;let name_len = u16::from_be_bytes(len_buf) as usize;let mut name_buf = vec![0u8; name_len];stream.read_exact(&mut name_buf)?;let filename = String::from_utf8_lossy(&name_buf).to_string();let mut size_buf = [0; 8];stream.read_exact(&mut size_buf)?;let file_size = u64::from_be_bytes(size_buf);println!("📥 接收大文件:{} ({} bytes)", filename, file_size);//创建保存文件的目录let mut path = PathBuf::from("received");std::fs::create_dir_all(&path)?;path.push(&filename);let mut file = File::create(path)?;let mut received: u64 = 0;let mut buffer = [0; 8192];//循环接收文件内容while received < file_size {let to_read = std::cmp::min(buffer.len() as u64, file_size - received) as usize;let n = stream.read(&mut buffer[..to_read])?;if n == 0 {break;}file.write_all(&buffer[..n])?;received += n as u64;}println!("✅ 文件接收完成,总计:{} bytes", received);Ok(())
}fn main() -> std::io::Result<()> {let listener = TcpListener::bind("0.0.0.0:7878")?;println!("🌐 等待客户端连接...");for stream in listener.incoming() {let stream = stream?;thread::spawn(|| {if let Err(e) = handle_client(stream) {eprintln!("❌ 错误:{}", e);}});}Ok(())
}

客户端:发送大文件(client.rs)

use std::net::TcpStream;
use std::io::{ Read, Write };
use std::fs::File;
use std::path::Path;fn main() -> std::io::Result<()> {let filepath = "VMware-Workstation.zip"; // 可以是任意大文件let path = Path::new(filepath);let filename = path.file_name().unwrap().to_str().unwrap();let mut file = File::open(path)?;let file_size = file.metadata()?.len();let mut stream = TcpStream::connect("127.0.0.1:7878")?;// 1. 文件名长度let name_len = filename.len() as u16;stream.write_all(&name_len.to_be_bytes())?;// 2. 文件名stream.write_all(filename.as_bytes())?;// 3. 文件大小stream.write_all(&file_size.to_be_bytes())?;// 4. 文件内容流式发送let mut buffer = [0; 8192];let mut sent: u64 = 0;while sent < file_size {let n = file.read(&mut buffer)?;if n == 0 {break;}stream.write_all(&buffer[..n])?;sent += n as u64;}println!("✅ 发送完成,总计:{} bytes", sent);Ok(())
}

6. 性能优化技巧

6.1 缓冲区管理

重用缓冲区而不是每次都创建新的
根据预期数据大小调整缓冲区大小
考虑使用BufReader和BufWriter进行缓冲I/O

use std::io::{BufReader, BufWriter};fn handle_client(stream: TcpStream) -> std::io::Result<()> {let mut reader = BufReader::new(&stream);let mut writer = BufWriter::new(&stream);let mut buffer = String::new();reader.read_line(&mut buffer)?;println!("Received: {}", buffer.trim());writer.write_all(b"HTTP/1.1 200 OK\r\n\r\nHello from server!")?;writer.flush()?;Ok(())
}

相关文章:

  • Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
  • 如何让非 TCP/IP 协议驱动屏蔽 IPv4/IPv6 和 ARP 报文?
  • gephi绘制网络拓扑图:批量给节点着色
  • spring boot使用HttpServletResponse实现sse后端流式输出消息
  • 代理篇12|深入理解 Vite中的Proxy接口代理配置
  • validate校验的使用
  • 50、文件上传-单文件与多文件上传的使用
  • 使用大模型预测巨细胞病毒视网膜炎的技术方案
  • JavaScript 标签加载
  • QT 第三讲 --- 基础篇 初用信号槽与命名规范
  • tomcat组件架构设计
  • 【仿生机器人】建模—— 图生3D 的几个办法
  • 2020年IS SCI2区,多样本和遗忘能力粒子群算法XPSO,深度解析+性能实测
  • 阿里云服务状态监控:实时掌握云服务健康状况
  • 基于cornerstone3D的dicom影像浏览器 第三十一章 从PACS服务加载图像
  • 生态系统服务(InVEST模型)供给与需求、价值核算技术及人类活动、重大工程项目、自然保护区、碳中和等
  • 如何在网页里填写 PDF 表格?
  • 免费在线PDF转图片工具
  • XXE漏洞知识
  • 免费PDF转图片软件