从具有Read :: read_to_string的TcpStream读取将挂起,直到远程端关闭连接

Chi*_*ico 15 io network-programming rust

我正在尝试在Rust中实现Haskell IRC bot教程,并且在连接后读取服务器发送给我的内容时遇到了一些困难.似乎发生的事情是我连接,从服务器读取~5 KB,然后大约240秒后,所有内容立即被转储,而不是逐行读取.连接由ping超时关闭,最终应该发生,因为我还没有ping-pong函数来回复.

这是我到目前为止所拥有的:

use std::io::{Read, Write};
use std::net::TcpStream;

fn main() {
    let mut stream = TcpStream::connect("irc.freenode.org:6667").unwrap();

    let _ = stream.write(b"NICK G-SERUFU\r\n");
    let _ = stream.write(b"USER G-SERUFU 0 * :brobot\r\n");
    let _ = stream.write(b"JOIN #tutbot-testing\r\n");

    let mut line = String::with_capacity(512);
    loop {
        let result = stream.read_to_string(&mut line);
        match result {
            Ok(n) => println!("Received {} bytes", n),
            _ => {}
        }
        line.clear();
    }
}
Run Code Online (Sandbox Code Playgroud)

当我修改循环a以使用数组而不是字符串时,我立即得到我期望的输出:

let mut line;
loop {
    line = [0; 512];
    let result = stream.read(&mut line);
    match result {
        Ok(n) => println!("Received {} bytes",n),
        _ => {},
    }
}
Run Code Online (Sandbox Code Playgroud)

我的结论是,stream.read_to_string(&mut line)某种程度上是罪魁祸首.为什么会出现这种情况?我有什么明显的东西可以忽略吗?

更具体地说,在第一种情况下,输出出现在ping超时之后,打印出以下内容:

//Around 4 minutes elapse before anything is printed to console
Received 5323 bytes
Received 0 bytes
Received 0 bytes
Received 0 bytes
//Continues to print "Received 0 bytes" since the connection has closed but I haven't broken out of the infinite loop
Run Code Online (Sandbox Code Playgroud)

在使用数组的第二种情况下,我几乎立即收到正确的输出:

Received 64 bytes
Received 51 bytes
Received 512 bytes
Received 512 bytes
Received 350 bytes
Received 512 bytes
Received 512 bytes
...
Run Code Online (Sandbox Code Playgroud)

She*_*ter 10

查看文档Read::read_to_string,重点是我的:

读取此源中的所有字节直到EOF,将它们放入buf.

同样地Read::read_to_end:

读取此源中的所有字节直到EOF,将它们放入buf.

值得注意的是,在第一个示例中,您没有读取512个字节,您预先分配512个字节的空间,然后读取每个字节,直到套接字关闭--4分钟后.

听起来你想要使用BufRead::read_line:

读取所有字节,直到达到换行字节(0xA字节),然后将它们附加到提供的缓冲区.

此函数将继续从基础流中读取(和缓冲)字节,直到找到换行符分隔符(0xA字节)或EOF.一旦找到,所有包含分隔符(如果找到)的字节都将附加到buf.

您还可以使用任何其他技术在返回之前读取固定数量的数据.一个这样的例子就是Read::take,它将限制你一次可以读取的总字节数.

  • 问题是关于`TCPStream`,据我所知,不能应用`BufRead::read_line`,不是吗? (2认同)
  • @PantelisSopasakis 抱歉我迟到了,但是不,你可以应用它。BufReader可以Buffer任何实现Read的类型,TcpStream也不例外。https://doc.rust-lang.org/std/io/struct.BufReader.html (2认同)