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));

}
posted @ 2026-04-20 23:36  lxd670  阅读(22)  评论(0)    收藏  举报