gpt4 book ai didi

linux - 如何从连接到套接字的 UnixStream 一次读取一点?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:13:17 25 4
gpt4 key购买 nike

我正在尝试从 UnixStream(在此代码中称为 socket)读取一些未知大小的数据。数据由 6 个字节的 header 组成,最后两个字节表示消息的其余部分应该有多长。

.into_buf()我调用的方法来自 Tokio 的 bytes crate 中的 IntoBuf 特性。

let mut header = [0u8; 6];
let response1 = self.socket.read(&mut header);
let mut cursor = header.into_buf();

let evt_code = cursor.get_u16_le();
let controller = cursor.get_u16_le();
let param_size = cursor.get_u16_le() as usize;

let mut param = vec![0u8; param_size];
let response2 = self.socket.read(&mut param);
let mut cursor = param.into_buf();

我遇到的问题是 response2 始终是 Err E_WOULDBLOCK,因为我的 UnixStream 连接到非阻塞套接字。似乎第一次调用 read() 是按预期读取 6 个字节,但随后只是丢弃了流中的其余内容。

我该如何解决这个问题/如何让 read() 将额外的数据留在流中?

看起来最简单的解决方案是让我的初始缓冲区变大,然后一次读取所有内容,但问题是我可以接收的最大可能消息超过 64KB。为每次读取分配或重新归零 64KB 缓冲区似乎很浪费,尤其是因为大多数消息都比这小得多。

最佳答案

我通过使用原始文件描述符而不是 UnixStream 并使用 MSG_PEEK 调用 recv() 来解决这个问题。

let mut header = [0u8; 6];

// need MSG_PEEK otherwise recv() clears the socket and we get EAGAIN when
// we try to read the socket again; this is the main reason for using a raw
// fd instead of a UnixStream
if unsafe { libc::recv(self.fd, header.as_mut_ptr() as *mut c_void, 6, libc::MSG_PEEK) } < 0 {
return Err(io::Error::last_os_error().into());
}

let mut cursor = header.into_buf();

let evt_code = cursor.get_u16_le();
let controller = cursor.get_u16_le();
let param_size = cursor.get_u16_le() as usize;


// since calling recv() with MSG_PEEK doesn't consume the header, we need to make
// this buffer 6 bytes bigger, but that's fine
let mut param = vec![0u8; param_size + 6];

if unsafe { libc::recv(self.fd, param.as_mut_ptr() as *mut c_void, param.len(), 0) } < 0 {
return Err(io::Error::last_os_error().into());
}

let mut cursor = param.into_buf();

关于linux - 如何从连接到套接字的 UnixStream 一次读取一点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58140920/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com