Rust 实现 tcp 服务器和客户端

Rust 实现 tcp 服务器和客户端

服务器端代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
by hzx 2020-08-01
一个简易的echo tcp server实现
*/

use std::io::{Error, Read, Write};
use std::net::{Shutdown, TcpListener, TcpStream};
use std::str;
use std::thread;
use std::time;

/// 该函数处理接入的连接
fn handle_client(mut stream: TcpStream) -> Result<(), Error> {
// 512字节的缓冲区读取数据
let mut buf = [0; 512];
// 设置read函数超时时间为60秒
stream
.set_read_timeout(Some(time::Duration::from_secs(60 as u64)))
.expect("set_read_timeout call failed");
// 获取远程节点的ip地址和端口号
let addr = stream.peer_addr().unwrap();

// 打印远程节点的ip地址和端口号
println!("accept a new connection from {}", addr);

// loop无限循环,直到read函数超时或者远程客户端关闭连接
loop {

// 以阻塞模式尝试从stea中接收数据
let res = stream.read(&mut buf);

// match语句判定读取结果
match res {
// 读取数据成功
Ok(bytes_read) => {
// 如果读取数据长度大于0
if bytes_read > 0 {
// 输出远程客户端ip地址、端口号以及接收的数据
println!(
"{}: {}",
addr,
str::from_utf8(&buf[..bytes_read])
.expect("Could not write buffer as string")
);
// echo 服务器将原数据返回
stream.write(&buf[..bytes_read])?;
}
}
// 读取过程出现错误
Err(e) => {
// 打印错误
println!("{}, error: {:?}", addr, e);

// 跳出loop循环
break;
}
}
// 线程休息100毫秒
thread::sleep(time::Duration::from_millis(100 as u64));
}
// 关闭连接
stream
.shutdown(Shutdown::Both)
.expect("shutdown call failed");
// 返回
return Ok(());
}

fn main() -> std::io::Result<()> {
// 创建一个TcpListener并绑定至本地8080端口
let listener = TcpListener::bind("127.0.0.1:8080").expect("bind error");
// 创建一个线程Vec管理线程
let mut thread_vec: Vec<thread::JoinHandle<()>> = Vec::new();

// 持续监听
for stream in listener.incoming() {
// 获取监听到的TcpStream,否则报错。
let stream = stream.expect("failed!");

// 创建一个新的线程并返回线程句柄
let handle = thread::spawn(move || {
handle_client(stream).unwrap_or_else(|error| eprintln!("{:?}", error));
});
// 将该线程句柄放入thread_vec中
thread_vec.push(handle);
}

// 遍历thread_vec中所有线程,等待线程执行完毕
for handle in thread_vec {
handle.join().unwrap();
}
// 返回结果
Ok(())
}

客户端代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
by hzx 2020-08-01
一个简易的echo tcp client 实现
*/

use std::io::{self, prelude::*, BufReader, Write};
use std::net::{Shutdown, TcpStream};
use std::str;
use std::thread;
use std::time;

fn main() -> std::io::Result<()> {
// 创建TcpStream并尝试与服务器建立连接
let mut stream = TcpStream::connect("127.0.0.1:8080")?;
// 设置60秒读取数据超时时间
stream
.set_read_timeout(Some(time::Duration::from_secs(60 as u64)))
.expect("set_read_timeout call failed");

// 从标准输入中持续读取数据
loop {
// 新建字符串input
let mut input = String::new();
//
// 从标准输入中读取数据
io::stdin()
.read_line(&mut input)
.expect("Failed to read from stdin");
// 如果input数据为exit,则退出程序
if input.trim() == String::from("exit") {
break;
}

// 向服务器发送数据
stream
.write(input.as_bytes())
.expect("Failed to write to stream");
// 使用BufReader读取stream中的数据
let mut reader = BufReader::new(&stream);
// buffer存储全部数据
let mut buffer: Vec<u8> = Vec::new();
// 尝试读取数据
let res = reader.read_until(b'\n', &mut buffer);
// 模式匹配数据
match res {
// 读取数据成功
Ok(bytes_read) => {
if bytes_read > 0 {
// 输出数据
println!(
"echo: {}",
str::from_utf8(&buffer).expect("Could not write buffer as string")
);
}
}
// 读取数据失败
Err(e) => {
// 打印错误
eprintln!("occur error {:?}", e);
// 退出循环
break;
}
}
// 睡眠100ms
thread::sleep(time::Duration::from_millis(100 as u64));
}
// 输出退出信息
println!("we are going to shutdown the connection");
// 关闭连接
stream.shutdown(Shutdown::Both).expect("shutdown error");
Ok(())
}