我有一个套接字,我想从中读取数据,直到当前字符等于CR或LR。当我逐字节读取它时,它运行良好。但是,当我在做read_to_end或read_to_string时,它会被冻结。我想知道,为什么以及如何解决它?从Rust中的套接字读取
另外,有没有更好的方式来阅读,直到当前字符相等CR或LR?
https://doc.rust-lang.org/nightly/std/io/trait.Read.html
我有一个套接字,我想从中读取数据,直到当前字符等于CR或LR。当我逐字节读取它时,它运行良好。但是,当我在做read_to_end或read_to_string时,它会被冻结。我想知道,为什么以及如何解决它?从Rust中的套接字读取
另外,有没有更好的方式来阅读,直到当前字符相等CR或LR?
https://doc.rust-lang.org/nightly/std/io/trait.Read.html
有没有更好的方式来读取,直到当前的字符是CR或LF?
是的。逐字节读取通常不是一个好主意。通常,您想要读取缓冲区,以减少系统调用次数。
使用read_to_end
或read_to_string
需要分配足够的内存来读取所有内容,这可能是一个DoS缺陷。
一种选择是编写自己的缓冲机制,执行连续调用read
。这可能很乏味。
您可以使用BufReader
来为任何读者添加缓冲,而不是编写自己的缓冲机制。 BufReader
执行BufRead
,它具有方法read_until
,可用于读取特定字节,但不能直接使用此方法,因为您有兴趣直到读取b'\n'
或b'\r'
。但是您可以编写一个实现Read
,将b'\r'
翻译为b'\n'
,然后使用read_until
和b'\n'
。下面是一个如何可以做到这一点一个例子:
use std::io::{self, Read, BufRead, BufReader};
pub struct ReadCrToLf<R: Read>(R);
impl<R: Read> Read for ReadCrToLf<R> {
fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
self.0.read(buffer).map(|s| {
for x in &mut buffer[..s] {
if *x == b'\r' {
*x = b'\n';
}
}
s
})
}
}
fn main() {
let read = b"test1\ntest2\rtest3\n";
let rt = ReadCrToLf(&read[..]);
let mut reader = BufReader::new(rt);
let mut buffer = Vec::new();
reader.read_until(b'\n', &mut buffer).unwrap();
assert_eq!(buffer, b"test1\n");
buffer.clear();
reader.read_until(b'\n', &mut buffer).unwrap();
assert_eq!(buffer, b"test2\n");
buffer.clear();
reader.read_until(b'\n', &mut buffer).unwrap();
assert_eq!(buffer, b"test3\n");
}
,如果你需要,因为你的分隔符只是ASCII字符(字节)b'\n'
和b'\r'
这也是困难的。 –
everything ...... –
'n一般情况下,你想读取一个缓冲区,所以你减少了系统调用的次数。“---你为什么认为'self.0.read(buffer).map(| s | {....'有较少的系统调用数量? –
来区分你能适应这种解决方案,您可以使用Read::bytes
与BufReader
。没有缓冲读取,bytes()
方法效率非常低,因为系统调用是为每个字节读取完成的。
论bytes()
顶部,你可以使用标准的迭代方法,像这样:
let buf_socket = BufReader::new(&socket);
let data: Vec<_> = buf_socket.bytes()
.take_while(|b| {
match *b {
Err(_) | Ok(b'\n') | Ok(b'\r') => false,
_ => true,
}
})
.collect();
这工作,因为迭代器是懒惰,比目前所需要的Bytes
迭代器无法读取更多的数据。
对我来说太困难了。 –
你可能是指LF? – starblue