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.
Here's what I have so far:
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();
}
}
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),
_ => {},
}
}
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?
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
...
Check out the docs for Read::read_to_string
, emphasis mine:
Read all bytes until EOF in this source, placing them into
buf
.
Likewise for Read::read_to_end
:
Read all bytes until EOF in this source, placing them into
buf
.
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.
It sounds like you want to use 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With