从带有 Read::read_to_string 的 TcpStream 读取挂起,直到连接被远程端关闭 [英] Reading from a TcpStream with Read::read_to_string hangs until the connection is closed by the remote end

查看:17
本文介绍了从带有 Read::read_to_string 的 TcpStream 读取挂起,直到连接被远程端关闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Rust 中实施 Haskell IRC 机器人教程,但在阅读内容时遇到了一些困难服务器在连接后发送给我.似乎发生的是我连接,从服务器读取约 5 KB,然后大约 240 秒后,所有内容立即转储,而不是逐行读取.连接因 ping 超时而关闭,这应该最终会发生,因为我还没有可以回复的 ping-pong 功能.

I'm attempting to implement the Haskell IRC bot tutorial in Rust and am having some difficulty reading what the server sends me after connecting. What seems to happen is that I connect, read ~5 KB from the server, and then roughly 240 seconds later everything is dumped at once instead of being read line-by-line. The connection is closed by a ping timeout, which should happen eventually, since I don't yet have a ping-pong function to reply with.

这是我目前所拥有的:

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
");
    let _ = stream.write(b"USER G-SERUFU 0 * :brobot
");
    let _ = stream.write(b"JOIN #tutbot-testing
");

    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 以使用数组而不是字符串时,我立即得到我期望的输出:

When I modify the loop a to use an array instead of a string, I immediately get the output I expect:

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) 不知何故是罪魁祸首.为什么会这样?有什么明显的东西我忽略了吗?

My conclusion is that stream.read_to_string(&mut line) is somehow the culprit. Why might that be the case? Is there something obvious that I'm overlooking?

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

To be more specific, in the first case the output appears after the ping timeout, upon which the following is printed:

//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

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

In the second case using the array, I receive the correct output almost immediately:

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

推荐答案

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

Check out the docs for Read::read_to_string, emphasis mine:

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

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

同样对于 Read::read_to_end:

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

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

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

Notably, you aren't reading 512 bytes in the first example, you are pre-allocating 512 bytes of space and then reading every byte until the socket closes - 4 minutes later.

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

It sounds like you want to use BufRead::read_line:

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

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

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

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,这将限制您一次可以读取的总字节数.

You can also any other technique that will read a fixed amount of data before returning. One such example would be Read::take, which will cap the total number of bytes you can read at a time.

这篇关于从带有 Read::read_to_string 的 TcpStream 读取挂起,直到连接被远程端关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆