使用Rust编程语言创建一个简单的文件传输系统。Rust以其性能、安全性和并发性功能而闻名,是构建网络应用程序的绝佳选择。
概述
我们的文件传输系统将包括一个客户端和一个服务器。客户端将向服务器发送文件,服务器将保存接收到的文件。
使用的技术:
- Rust编程语言
- 标准库(
std::net
,std::fs
,std::io
) - TCP/IP网络
实现
服务器端
首先从服务器端实现开始。服务器将监听传入的连接,并将接收到的文件保存到磁盘上。
Command::Server {
host,
port
} =>{
let server = format!("{}:{}",host.clone().unwrap(),port.clone().unwrap());
let listener = TcpListener::bind(server.as_str()).expect("ip绑定失败");
//incoming返回此侦听器上接收的连接的迭代器。
// 返回的迭代器永远不会返回 None,也不会生成对等方的 SocketAddr 结构。遍历它等效于在循环中调用 TcpListener::accept。
for stream in listener.incoming(){
match stream {
Ok(stream) =>{
handle_client(stream);
}
Err(e) => {
eprintln!("tcp 连接失败: {}", e);
}
}
}
},
use std::fs::File;
use std::io::{Read, Write};
use std::net::TcpStream;
struct FileMessage {
filename: String,
file_size: u64,
file_data: Vec<u8>,
}
fn encode_file_message(msg: FileMessage) -> Vec<u8> {
let mut encoded_message = Vec::<u8>::new();
encoded_message.push(msg.filename.len() as u8);
encoded_message.extend_from_slice(&msg.filename.as_bytes());
encoded_message.extend_from_slice(&msg.file_size.to_le_bytes());
encoded_message.extend_from_slice(&msg.file_data);
encoded_message
}
fn decode_file_message(data: &[u8]) -> FileMessage {
let filename_length = data[0] as usize;
let filename = String::from_utf8_lossy(&data[1..1 + filename_length]).into_owned();
let file_size = u64::from_le_bytes(data[1 + filename_length..9 + filename_length].try_into().unwrap());
let file_data = data[9 + filename_length..].to_vec();
FileMessage {
filename,
file_size,
file_data,
}
}
pub fn handle_client(mut stream: TcpStream) {
let mut buffer = [0; 1024];
match stream.read(&mut buffer) {
Ok(bytes_read) => {
let received_data = &buffer[..bytes_read];
let received_message = decode_file_message(received_data);
save_file(&received_message.filename, &received_message.file_data).expect("Error saving file");
}
Err(e) => panic!("读取字节流失败:{}", e)
}
}
fn save_file(filename: &str, data: &[u8]) -> std::io::Result<()> {
let file = format!("{}+successfully", filename);
let mut file = File::create(file)?;
file.write_all(data)?;
Ok(())
}
客户端
接下来,实现客户端。客户端将与服务器建立连接并发送文件。
Command::Client {
send,
host,
port
} =>{
let server = format!("{}:{}",host.clone().unwrap(),port.clone().unwrap());
let mut stream = TcpStream::connect(server).unwrap();
if let Some(filename) = send{
match send_file(&mut stream,filename) {
Ok(_rs) =>{
println!("发送成功!")
}
Err(e) => panic!("文件发送失败:{}",e)
}
}
},
use std::fs::File;
use std::io::{Read, Write};
use std::net::TcpStream;
struct FileMessage {
filename: String,
file_size: u64,
file_data: Vec<u8>,
}
fn encode_file_message(msg: FileMessage) -> Vec<u8> {
let mut encoded_message = Vec::<u8>::new();
encoded_message.push(msg.filename.len() as u8);
encoded_message.extend_from_slice(&msg.filename.as_bytes());
encoded_message.extend_from_slice(&msg.file_size.to_le_bytes());
encoded_message.extend_from_slice(&msg.file_data);
encoded_message
}
fn decode_file_message(data: &[u8]) -> FileMessage {
let filename_length = data[0] as usize;
let filename = String::from_utf8_lossy(&data[1..1 + filename_length]).into_owned();
let file_size = u64::from_le_bytes(data[1 + filename_length..9 + filename_length].try_into().unwrap());
let file_data = data[9 + filename_length..].to_vec();
FileMessage {
filename,
file_size,
file_data,
}
}
pub fn send_file(stream: &mut TcpStream, filename: &str) -> std::io::Result<()> {
let mut file = File::open(filename)?;
let mut file_data = Vec::new();
file.read_to_end(&mut file_data)?;
let file_message = FileMessage {
filename: filename.to_owned(),
file_size: file_data.len() as u64,
file_data,
};
let encoded_message = encode_file_message(file_message);
stream.write_all(&encoded_message)?;
Ok(())
}
通信协议
文件传输系统使用了一个简单的通信协议:
-
消息结构:每个消息包括:
- 文件名长度(1字节)
- 文件名(可变长度)
- 文件大小(8字节,小端序)
- 文件数据(可变长度)
-
编码:在通过网络发送之前,将FileMessage结构编码为字节数组。
-
解码:接收到的字节数组被解码回FileMessage结构。
结论
使用Rust构建了一个简单的文件传输系统。实现了客户端和服务器端,并探讨了用于在网络上传输文件的通信协议。