io - 使用 Read::read_to_string 从 TcpStream 读取会挂起,直到连接被远程端关闭

标签 io rust network-programming

我正在尝试实现 Haskell IRC bot tutorial在 Rust 中,我在阅读连接后服务器发送给我的内容时遇到了一些困难。似乎发生的是我连接,从服务器读取 ~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();
    }
}

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

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

我的结论是 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

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

Received 64 bytes
Received 51 bytes
Received 512 bytes
Received 512 bytes
Received 350 bytes
Received 512 bytes
Received 512 bytes
...

最佳答案

查看 docs for Read::read_to_string ,强调我的:

Read all bytes until EOF in this source, placing them into buf.

同样适用于 Read::read_to_end :

Read all bytes until EOF in this source, placing them into buf.

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

听起来您想使用 BufRead::read_line :

Read all bytes until a newline byte (the 0xA byte) is reached, and append them to the provided buffer.

This function will continue to read (and buffer) bytes from the underlying stream until the newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes up to, and including, the delimiter (if found) will be appended to buf.

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

关于io - 使用 Read::read_to_string 从 TcpStream 读取会挂起,直到连接被远程端关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50818660/

相关文章:

haskell - 什么时候使用 ByteString,什么时候不使用?

error-handling - 为什么?运算符(operator)报告错误 "the trait bound NoneError: Error is not satisfied"?

networking - tcp程序无法监听80端口

rust - 如何使用自定义 llc 编译 Rust 程序?

c++ - 在 sockaddr 指针和 sockaddr_in 指针之间转换

c - 通过网络发送的填充结构

file - .net 中的递归文件搜索

java - 扫描仪在使用 next() 或 nextFoo() 后跳过 nextLine()?

java - Haskell 程序删除注释

generics - 收集到Vec与&Vec