TCPStream如何知道消息何时完成?

TCPStream如何知道消息何时完成?,tcp,rust,Tcp,Rust,据我所知,TCPStream不知道何时从客户端收到完整的消息,但信息到达字节流 然而,当我在Rust中执行标准的“Hello World”TCPStream示例时,我正在从流中读取完整的HTTP消息。当我发送两条或多条消息时,它们将相应地分开 这怎么可能 use std::io::prelude::*; use std::net::TcpListener; use std::net::TcpStream; fn main() { let listener = TcpListener::

据我所知,
TCPStream
不知道何时从客户端收到完整的消息,但信息到达字节流

然而,当我在Rust中执行标准的“Hello World”
TCPStream
示例时,我正在从流中读取完整的HTTP消息。当我发送两条或多条消息时,它们将相应地分开

这怎么可能

use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;

fn main() {
    let listener = TcpListener::bind("127.0.0.1:8080").unwrap();

    for stream in listener.incoming() {
        let stream = stream.unwrap();
        handle_connection(stream);
    }
}

fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 512];
    stream.read(&mut buffer).unwrap();
    println!("{}", String::from_utf8_lossy(&buffer[..]));
}

当我减小缓冲区大小时,HTTP消息将被剪切,新消息将从头开始。我会以某种方式假设我必须自己管理一条新的HTTP消息的结束和开始?

观察到效果的原因在于一般的读者行为

TcpStream
上的
read
方法由
read
特性提供。引用此方法的参数:

将此源中的一些字节拉入指定的缓冲区,返回读取的字节数

注意“some bytes”位:
read
方法一直读取,直到缓冲区被填满或读取的数据耗尽为止。对于
TcpStream
,这种耗尽可能发生在两种情况下:

  • 请求已完全发送,另一方根本不提供更多数据
  • 或者有一些网络延迟,只有部分请求已经在这里了
在测试中,您似乎总是遇到第一种情况:当您调用
read
时,请求已经被完全传输,并且它适合缓冲区,因此可以一直读取到最后。但是,当缓冲区太小时,您将无法一次获取整个消息,因此您必须在同一个流上再次调用
read
,以获取其余消息


在实际代码中,您应该在读取请求时对其进行解析,以确定您遇到了哪种情况:请求是完全到达还是必须再次读取。

在非常低的级别上,客户端使用基本的Unix操作将字节放入套接字,服务器使用
nread=
从套接字中取出字节

read()
write()
与套接字一起使用时,它们不能保证将
write()
拆分为多个
read()
或将多个
write()
合并为一个大的
read()
的行为。任何事情都可能发生,只要客户端写入的字节最终将由服务器按照客户端写入字节的相同顺序读取(假设网络连接不会因某种原因中断)


在您的特定情况下,客户端可能发出了两个
write()
调用,这些调用在TCP层被转换为两个相应的数据包。服务器进程正在等待
read()
调用。服务器操作系统设法唤醒服务器进程,并在第二个数据包到达或以其他方式通过服务器操作系统之前将第一个数据包的内容提供给它。因此,服务器进程发现自己正好有一个完整的HTTP请求需要处理。

因为你很幸运。你能详细说明一下吗?这回答了你的问题吗,这通常是与TCP混淆的一个共同点;它不是铁锈专用的。如果您搜索“TCP消息边界”或其他类似的语言不可知查询,则会有更多类似的问题。