std::net::TcpListener和TcpStream
1.Tcp连接
-
服务端用
TcpListener监听端口 -
客户端用
TcpStream连接端口 -
连接成功后,双方都用
TcpStream收发数据
2.TcpListener
TCP套接字服务器,侦听连接。
2.1 用法
2.1.1 监听指定端口
use std::net::TcpListener;
fn main() {
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
println!("Server listening on 127.0.0.1:8080");
// Result<TcpStream, Error>
for stream in listener.incoming() {
println!("stream {:?}", stream);
}
}
2.1.2 监听端口(选择)
第一个监听失败,选择第二个监听
use std::net::{SocketAddr, TcpListener};
fn main() {
let addrs = [
SocketAddr::from(([127, 0, 0, 1], 80)),
SocketAddr::from(([127, 0, 0, 1], 443)),
];
let listener = TcpListener::bind(&addrs[..]).unwrap();
}
2.2 方法
2.2.1 bind
创建一个TCP监听,并绑定到指定的地址。返回
TcpListener
use std::net::TcpListener;
// 创建tcp监听,绑定到127.0.0.1:80
let listener = TcpListener::bind("127.0.0.1:80").unwrap();
绑定选择
如何绑定127.0.0.1:80失败,那么尝试绑定127.0.0.1:443
use std::net::{SocketAddr, TcpListener};
let addrs = [
SocketAddr::from(([127, 0, 0, 1], 80)),
SocketAddr::from(([127, 0, 0, 1], 443)),
];
let listener = TcpListener::bind(&addrs[..]).unwrap();
2.2.2 accept
函数将阻塞调用线程,直到建立新的 TCP 连接为止
use std::net::TcpListener;
fn main() {
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
match listener.accept() {
// socket: TcpStream
// addr: SocketAddr
Ok((socket, addr)) => {
println!("socket: {:?}", socket);
println!("addr: {}", addr);
}
Err(e) => {
println!("Error: {}", e);
}
}
}
socket: TcpStream { addr: 127.0.0.1:8080, peer: 127.0.0.1:62499, fd: 4 }
addr: 127.0.0.1:62499
2.2.3 local_addr
返回监听的地址和端口
use std::net::TcpListener;
fn main() {
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
// Resilt<SockertAddr, Err>
let s = listener.local_addr();
match s {
Ok(addr) => {
println!("addr: {}", addr);
println!("ip: {}", addr.ip());
println!("port: {}", addr.port());
},
Err(e) => panic!("{}", e),
}
}
addr: 127.0.0.1:8080
ip: 127.0.0.1
port: 8080
2.2.4 try_clone
创建一个新的
TcpListener实例,它与原始监听器共享相同的底层套接字
- 同一时刻只有一个accept可以捕获
use std::net::TcpListener;
use std::thread;
fn main() {
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
let listener1 = listener.try_clone().unwrap();
let handle = thread::spawn(move || {
println!("Cloned listener waiting for connection...");
match listener1.accept() {
Ok((stream, addr)) => {
println!("Cloned listener accepted connection from: {}", addr);
}
Err(e) => println!("Cloned listener error: {}", e),
}
});
println!("Listening on {:?}", listener.accept());
handle.join().unwrap();
}
Cloned listener waiting for connection...
Listening on Ok((TcpStream { addr: 127.0.0.1:8080, peer: 127.0.0.1:52710, fd: 5 }, 127.0.0.1:52710))
Cloned listener accepted connection from: 127.0.0.1:52725
2.2.5 incoming
惰性阻塞等待连接,是一个无限迭代器
listener.incoming()返回一个Result<TcpStream, Error>
use std::net::TcpListener;
use std::thread;
fn main() {
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
let listener1 = listener.try_clone().unwrap();
let t1 = thread::spawn(move || {
println!("listener waiting for connection[t1]...");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
println!("listener[t1] {:?}", stream);
}
Err(e) => {
println!("listener[t2] error: {:?}", e);
}
}
}
});
let t2 = thread::spawn(move || {
println!("listener waiting for connection[t2]...");
for stream in listener1.incoming() {
match stream {
Ok(stream) => {
println!("listener[t2] {:?}", stream);
}
Err(e) => {
println!("listener[t2] error: {:?}", e);
}
}
}
});
t1.join().unwrap();
t2.join().unwrap();
}
listener waiting for connection[t1]...
listener waiting for connection[t2]...
listener[t1] TcpStream { addr: 127.0.0.1:8080, peer: 127.0.0.1:61805, fd: 5 }
listener[t2] TcpStream { addr: 127.0.0.1:8080, peer: 127.0.0.1:61809, fd: 5 }
listener[t1] TcpStream { addr: 127.0.0.1:8080, peer: 127.0.0.1:61811, fd: 5 }
listener[t2] TcpStream { addr: 127.0.0.1:8080, peer: 127.0.0.1:61812, fd: 5 }
3.TcpStream
打开到远程主机的
TCP连接
3.1 用法connect
3.1.1 正确连接
use std::net::TcpStream;
fn main() {
// 连接到服务器
let stream_result = TcpStream::connect("127.0.0.1:8080");
println!("stream_result: {:?}", stream_result)
}
stream_result: Ok(TcpStream { addr: 127.0.0.1:50898, peer: 127.0.0.1:8080, fd: 3 })
3.1.2 3.1.1错误连接
use std::net::TcpStream;
fn main() {
// 连接到服务器
let stream_result = TcpStream::connect("127.0.0.1:8888");
println!("stream_result: {:?}", stream_result)
}
stream_result: Err(Os { code: 61, kind: ConnectionRefused, message: "Connection refused" })
3.1.3 连接服务器(选择)
第一个不成功,会连接第二个
use std::net::{SocketAddr, TcpStream};
fn main() {
let addrs = [
SocketAddr::from(([127, 0, 0, 1], 8080)),
SocketAddr::from(([127, 0, 0, 1], 8081)),
];
if let Ok(stream) = TcpStream::connect(&addrs[..]) {
println!("Connected to the server!");
} else {
println!("Couldn't connect to server...");
}
}
3.1.4 连接设置超时connect_timeout
use std::net::{TcpStream, SocketAddr};
use std::time::Duration;
fn main() {
// 连接到服务器
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
let stream_result = TcpStream::connect_timeout(&addr, Duration::from_secs(5));
if let Ok(mut stream) = stream_result {
println!("stream: {:?}", stream);
} else {
println!("无法连接到服务器");
}
}
stream: TcpStream { addr: 127.0.0.1:52059, peer: 127.0.0.1:8080, fd: 3 }
3.2 读写操作
读用 BufRead,写用 BufWrite + write_all
3.2.1 读取
一大坨数据粘在一起,自己切分
3.2.1.1 stream.read返回值
Result<usize>
use std::net::TcpListener;
use std::io::Read;
// use std::time::Duration;
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
for stream_result in listener.incoming() {
println!("Incoming connection");
if let Ok(mut stream) = stream_result {
let mut buf = [0; 1024];
// 返回Result<usize>
let read_result = stream.read(&mut buf);
println!("read_result: {:?}", read_result);
} else {
break;
}
println!("Connection closed");
};
}
Incoming connection
read_result: Ok(12)
Connection closed
3.2.1.2 stream.read
use std::net::TcpListener;
use std::io::Read;
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
for stream_result in listener.incoming() {
println!("Incoming connection");
if let Ok(mut stream) = stream_result {
let mut buf = [0; 1024];
// stream.read返回Result<usize>
// 提取读取字节数
let read_bytes = stream.read(&mut buf).unwrap();
println!("read_bytes: {}", read_bytes);
println!("buf: {}", String::from_utf8_lossy(&buf[..read_bytes]));
} else {
break;
}
println!("Connection closed");
};
}
Incoming connection
read_bytes: 12
buf: hello world
Connection closed
3.2.1.3 BufReader
use std::net::TcpListener;
// 必须导入这两个
use std::io::{BufRead, BufReader};
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
// 监听连接
for stream_result in listener.incoming() {
println!("Incoming connection");
if let Ok(stream) = stream_result {
// 把 stream 包进 BufReader
let reader = BufReader::new(stream);
// 直接用 lines() 循环,自动按行读
// 这里的 for 循环 代替了你原来的 loop!
for line in reader.lines() {
match line {
Ok(content) => {
println!("收到一行:{}", content);
}
Err(_) => {
println!("客户端断开或出错");
break;
}
}
}
}
println!("Connection closed");
}
}
BufReader按行获取
- lines = 自动读字节 + 自动分行 + 自动转字符串(String)
use std::net::TcpStream;
use std::io::{Write, BufRead, BufWriter, BufReader};
fn main() {
// 连接到服务器
let stream_result = TcpStream::connect("127.0.0.1:8080");
if let Ok(stream) = stream_result {
let mut buf_reader_strwam = BufReader::new(stream.try_clone().unwrap());
let mut buf_write_stream = BufWriter::new(stream);
// 发送数据, 返回发送的字节数
buf_write_stream.write_all(b"Hello, server!").unwrap();
buf_write_stream.flush().unwrap();
// 按行获取,需要导入 std::io::BufRead
for line in buf_reader_strwam.lines() {
println!("{:?}", line);
}
} else {
println!("无法连接到服务器");
}
}
Ok("Hello, server!")
Ok("你好")
3.2.2 写入
-
stream.write:发一次,调用一次系统 → 慢
-
BufWriter:先攒内存,批量发 → 快
3.2.2.1 stream.write返回值
返回
Result<usize>
use std::net::TcpStream;
use std::io::{Write, Read};
fn main() {
// 连接到服务器
let stream_result = TcpStream::connect("127.0.0.1:7878");
if let Ok(mut stream) = stream_result {
// 发送数据, 返回发送的字节数
let write_result = stream.write(b"Hello, server!");
println!("write_result: {:?}", write_result);
} else {
println!("无法连接到服务器");
}
}
write_result: Ok(14)
3.2.2.2 stream.write
stream.write()也可能写不完
use std::net::TcpStream;
use std::io::{Write, Read};
fn main() {
// 连接到服务器
let stream_result = TcpStream::connect("127.0.0.1:8080");
if let Ok(mut stream) = stream_result {
// 发送数据, 返回发送的字节数
let write_num = stream.write(b"Hello, server!").unwrap();
println!("已发送{}字节数据", write_num);
} else {
println!("无法连接到服务器");
}
}
已发送14字节数据
3.2.2.3 BufWriter
BufWriter::new(stream)包装stream- write_all和write区别
- write_all会自动处理缓冲区,确保数据全部写入
- write会返回写入的字节数,需要手动处理缓冲区(有可能只写了一部分数据)
- 执行完都需要
stream.flush().unwrap()
write
能写多少写多少,不保证全部写完
use std::io::{BufWriter, Write};
use std::net::TcpStream;
fn main() {
let stream = TcpStream::connect("127.0.0.1:7878").unwrap();
let mut buf_write_stream = BufWriter::new(stream);
//写入数据
for i in 0..3 {
let write_num = buf_write_stream.write(format!("hello {}\n", i).as_bytes()).unwrap();
println!("write num: {}", write_num);
}
// 必须刷新,发送!
buf_write_stream.flush().unwrap();
}
write num: 8
write num: 8
write num: 8
write_all
保证全部写完,否则报错
use std::io::{BufWriter, Write};
use std::net::TcpStream;
fn main() {
let stream = TcpStream::connect("127.0.0.1:7878").unwrap();
let mut buf_write_stream = BufWriter::new(stream);
//写入数据
for i in 0..3 {
buf_write_stream.write_all(format!("hello {}\n", i).as_bytes()).unwrap();
}
// 必须刷新,发送!
buf_write_stream.flush().unwrap();
}
3.2.3 超时
| 方式 | 超时来源 | 超时返回 |
|---|---|---|
stream.read() |
TcpStream | Err(TimedOut) |
BufRead.lines() |
TcpStream | Err(TimedOut) |
stream.write() |
TcpStream | Err(TimedOut) |
BufWrite.write()/BufWrite.all_write() |
TcpStream | Err(TimedOut) |
3.2.3.1 set_read_timeout读取超时
设置超时后,
stream.read返回Err
use std::net::TcpListener;
use std::io::Read;
use std::time::Duration;
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
for stream_result in listener.incoming() {
println!("Incoming connection");
if let Ok(mut stream) = stream_result {
stream.set_read_timeout(Some(Duration::from_millis(100))).unwrap();
let mut buf = [0; 1024];
// 返回Result<usize>
let read_result = stream.read(&mut buf);
println!("read_result: {:?}", read_result);
} else {
break;
}
println!("Connection closed");
};
}
Incoming connection
read_result: Err(Os { code: 35, kind: WouldBlock, message: "Resource temporarily unavailable" })
Connection closed
3.2.3.2 set_write_timeout写入超时
只要缓冲区没满,
write永远立即成功,永远不会超时!
use std::net::TcpStream;
use std::io::Write;
use std::time::Duration;
fn main() {
let mut stream = TcpStream::connect("127.0.0.1:7878").unwrap();
println!("已连接服务器");
// 设置写超时 1 秒
stream.set_write_timeout(Some(Duration::from_secs(1))).unwrap();
// 无限写数据,一定会塞满缓冲区,触发超时!
loop {
let write_result = stream.write(&[0; 1024]);
println!("write_result: {:?}", write_result);
if write_result.is_err() {
break;
}
}
}
write_result: Ok(1024)
write_result: Ok(1024)
...
...
write_result: Err(Os { code: 32, kind: BrokenPipe, message: "Broken pipe" })
4.关闭连接
- 自动关闭
- 执行drop(stream)
- stream离开作用域
| 方式 | 行为 | 用途 |
|---|---|---|
shutdown() |
礼貌地关闭连接方向 | 协议级别的优雅关闭 |
drop() / 作用域结束 |
立即断开整个连接 | 资源清理 |
4.1 shutdown
- std::net::Shutdown枚举
- Shutdown::Write:关闭写入方向,发送 FIN 包
- Shutdown::Read:关闭读取方向
- Shutdown::Both:同时关闭读写方向
use std::net::{TcpStream, Shutdown};
fn main() {
// 连接到服务器
let stream_result = TcpStream::connect("127.0.0.1:8080");
if let Ok(mut stream) = stream_result {
// 手动关闭连接
stream.shutdown(Shutdown::Both).expect("无法关闭流");
} else {
println!("无法连接到服务器");
}
}
5.案例
5.1 使用原生read和write
设置
buf大小,接受数据
服务端
use std::net::TcpListener;
use std::io::{Read, Write};
fn main() {
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
println!("Server listening on 127.0.0.1:8080");
// Result<TcpStream, Error>
for result_stream in listener.incoming() {
println!("result_stream {:?}", result_stream);
match result_stream {
Ok(mut stream) => {
// 接收数据
let mut buf = [0; 1024];
let read_num = stream.read(&mut buf).unwrap();
println!("read_num {:?}", read_num);
// 转换为字符串
let mut s = String::from_utf8_lossy(&buf[..read_num]);
println!("s {:?}", s);
// 修改字符串
s += "\n你好\n";
// 发送数据
let send_num = stream.write(&s.as_bytes()).unwrap();
println!("send_num {:?}", send_num)
},
Err(e) => {
println!("Error: {}", e);
}
}
}
}
连接端
use std::net::TcpStream;
use std::io::{Write, Read};
fn main() {
if let Ok(mut stream) = TcpStream::connect("127.0.0.1:8080") {
println!("Connected to the server!: {:?}", stream);
// 发送数据
let send_num = stream.write(b"Hello, world!");
println!("Sent: {:?}", send_num);
// 接收数据
let mut buf = [0; 1024];
let read_num = stream.read(&mut buf).unwrap();
// 转为字符串
let s = String::from_utf8_lossy(&buf[..read_num]);
println!("buf {:?}", s);
} else {
println!("Couldn't connect to server...");
}
}
5.2 tcp获取大数据时
buf设置1024,然后获取的内容存取到vec中
- TCP 不保证消息边界,数据一定会合并
- 必须自己用 换行符 / 分隔符 / 长度 来拆包
接收端
当发送端结束连接时会重新等待。
use std::net::TcpListener;
use std::io::Read;
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
for stream_result in listener.incoming() {
println!("Incoming connection");
if let Ok(mut stream) = stream_result {
// 1.设置buf大小
let mut buf = [0;1024];
let mut read_info = Vec::new();
loop {
// 2.获取最大1024个数据
let bytes_num = stream.read(&mut buf).unwrap();
// 3.判断是否已经收完了
if bytes_num == 0 {
println!("EOF断开了");
break;
}
// 4.把接受的数据放入vec里
// 主要,需要bytes_num(接受实际的字节数)
read_info.extend_from_slice(&buf[..bytes_num]);
}
// 5.把vec转为字符串
let s = String::from_utf8_lossy(&read_info);
println!("{}", s);
} else {
break;
}
println!("Connection closed");
};
}
Incoming connection
EOF断开了
hello 0hello 1hello 2
Connection closed
发送端
stream离开作用域关闭 = 自动帮你调用了 shutdown + 清理资源
use std::io::Write;
use std::net::TcpStream;
use std::time::Duration;
use std::thread;
fn main() {
let mut stream = TcpStream::connect("127.0.0.1:7878").unwrap();
// 发送3次数据
for i in 0..3 {
stream.write(format!("hello {}", i).as_bytes()).unwrap();
}
// 手动调用shutdown中断tcp链接
stream.shutdown(std::net::Shutdown::Both).unwrap();
thread::sleep(std::time::Duration::from_secs(30));
}

浙公网安备 33010602011771号