sockets - 如何将套接字中的数据读取到现有缓冲区的偏移量中?

标签 sockets tcp rust

根据我对 TCP 的理解,如果我将 X 个字节发送到一个套接字,它几乎可以保证它会到达那里,尽管有效负载可能会 split 并分成两个单独的部分到达(所以如果我等待一个 25 字节的数据包,我可能会得到 20 个字节,然后在下一次读取时再得到 5 个字节)。我从未见过这种情况发生,但我希望在发生这种情况时得到保护。

在过去,我通常设计我的套接字读取来解决这个问题——将传入的字节读入缓冲区,然后不断地检查缓冲区的大小。如果整个数据包有足够的数据,则处理该数据包,从缓冲区前面移除字节,然后继续。

我现在正尝试在 Rust 中编写一个类似的系统,使用 mio 作为 TCP 套接字。我的缓冲区只是一个数组:[u8; MAX_BUFFER_SIZE] 这是我的套接字读取代码:

loop {
    // Read until there are no more incoming bytes
    match socket.read(&mut buffer) {
        Ok(0) => {
            // Socket is closed, Client has disconnected!
            // (perform disconnection here)
            break;
        },
        Ok(read_bytes) => {
            println!("Read {} bytes from client", read_bytes);
        },
        Err(e) => {
            if e.kind() == io::ErrorKind::WouldBlock {
                // Socket is not ready anymore, stop reading
                break;
            }
        }
    }
}

这不支持读取任何拆分数据,因为 read 函数只是覆盖缓冲区开头的数据,而不是将每个后续调用附加到末尾。在 C# 和 C++ 中,您可以向等效调用提供一个偏移参数以允许此行为,但我不知道如何使用 mio 执行此操作。我找不到任何偏移参数这一事实让我相信我在理解 read 函数时遗漏了一些重要的东西。

我将如何编写解决此问题的套接字读取程序?

最佳答案

The fact that I can't find any offset parameter leads me to believe that I am missing something important

是的,但它与套接字无关。 Rust 有切片,这是一种更通用的解决方案。要获取缓冲区的子集,请从所需的偏移量开始切片。数据将被读入与原始缓冲区的偏移量相同的切片的开头:

socket.read(&mut buffer[offset..])

当你完成读取时,你可以采取一个切片来防止查看缓冲区中无用的尾随数据:

let my_data = &buffer[..total_read_bytes];
// do something with my_data

一个完整的例子:

use std::io::prelude::*;

const MAX_LEN: usize = 64;

fn main() {
    let dummy_data = b"this is a very long bit of data";
    let mut dummy_data = &dummy_data[..];

    let mut buffer = [0; MAX_LEN];

    let mut offset = 0;
    offset += dummy_data
        .by_ref()
        .take(4)
        .read(&mut buffer[offset..])
        .unwrap();
    offset += dummy_data
        .by_ref()
        .take(4)
        .read(&mut buffer[offset..])
        .unwrap();

    let final_data = &buffer[..offset];

    let s = std::str::from_utf8(final_data);
    println!("{:?}", s);
    assert_eq!(s, Ok("this is "));
}

您可能还对 Read::read_exact 感兴趣:

This function reads as many bytes as necessary to completely fill the specified buffer buf.

关于sockets - 如何将套接字中的数据读取到现有缓冲区的偏移量中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48852831/

相关文章:

java - 线程和观察者模式。我怎样才能让一个线程通知所有其他线程并执行某个方法/事物?

ios - 无论如何,有没有办法从 Swift 中的 socket.io 方法返回一些东西?

objective-c - 使用 uitabbarcontroller 在 iOS 中管理套接字

c++ - 将 double 转换并连接到字节数组

tcp - 我应该使用的端口范围是多少?

amazon-s3 - 如果未找到环境变量,我如何回退到文件中的凭据?

generics - 通过其自身的通用生命周期(trait Bar <'a>: ' a)来限制特征是什么意思?

c# - Python 到 C# TCP 传输损坏超过 1523 个字节的数据

c# - NetworkStream 获取 System.IO.IOException : Unable to write data to the transport connection

rust - 我可以在没有 Cargo.toml 的情况下使用 Cargo 安装库吗?