确定流结束

3 rust

我为网络服务器做了一个循环。在 Windows 客户端上我没有遇到任何问题,但在 Linux 客户端上服务器没有响应请求。

问题:我发现 if request_size % buffer_size == 0then 循环再次运行以等待更多数据。

问题:是否有一种有效的方法来读取数据,同时考虑到慢速连接和丢包的连接。(不仅仅是使用 non_blocking 或 nodelay。)

let listener = TcpListener::bind("127.0.0.1:80").unwrap();

while let Ok((mut stream, _)) = listener.accept() {
  let mut data: Vec<u8> = Vec::new();
  let mut buf = [0u8; 32];
  while let Ok(size) = stream.read(&mut buf) {
    data.extend(buf[..size].iter());
    if size != buf.len() { break; }
  }

  // do something with the data
}
Run Code Online (Sandbox Code Playgroud)

我可以增加缓冲区大小,但这并不能解决问题。

Cry*_*jar 5

首先,为了可靠地检测 EOF,您应该测试返回sizeRead::read零而不是缓冲区大小,因为如果您有“慢速连接”,您可能无法立即获得足够的数据来填充整个缓冲区,从而导致循环过早中的消息不完整data


基本上有 3 种方法可以确保收到完整的消息:

  • 读取直到EOF
  • 读取固定大小的消息
  • 对一些“内容长度”进行编码并读取那么多字节

请注意,只有最后两个变体允许您的客户端最终通过同一流发送更多数据。另请注意,这两种变体可以通过相对容易地实现Read::read_exact

另外请注意,如果您不信任您的客户端,设置TcpStream::set_read_timeout相当长的超时(例如 2 分钟)可能会有所帮助。

读取直到EOF

这可能是最简单的,根据您的标题和代码,这可能是您想要的方法。然而,要生成 EOF,客户端必须至少关闭其写入通道。因此,如果您的服务器陷入困境read,我假设您忘记关闭客户端(我必须在这里猜测)。

在服务器端,如果您确实想读取直到EOF,则不需要自己循环,只需使用Read::read_to_end实用程序函数即可。以下是客户端和服务器的示例,其中客户端发送一条EOF 终止的消息:

use std::io::Read;
use std::io::Write;
use std::net::TcpListener;
use std::net::TcpStream;

// --- Client code
const SERVER_ADDR: &str = "localhost:1234";
pub fn client() {
    let mut socket = TcpStream::connect(SERVER_ADDR).expect("Failed to connect");
    // Send a 'single' message, the flushes kinda simulates a very slow connection
    for _ in 0..3 {
        socket.write(b"Hello").expect("Failed to send");
        socket.flush().unwrap();
    }
    // Instead of shutdow, you can also drop(socket), but than you can't read.
    socket.shutdown(std::net::Shutdown::Write).unwrap();
    // go reading, or whatever
}

// --- Server code
const SERVER_BIND: &str = "127.0.0.1:1234";
pub fn server() {
    let listener = TcpListener::bind(SERVER_BIND).expect("Failed to bind");
    while let Ok((stream, _)) = listener.accept() {
        let _ = handle_client(stream); // don't care if the client screwed up
    }
}
pub fn handle_client(mut socket: TcpStream) -> std::io::Result<()> {
    let mut data: Vec<u8> = Vec::new();
    // Read all bytes until EOF
    socket.read_to_end(&mut data)?;
    println!("Data: {:?}", data); // or whatever
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)