Reading from TcpStream results in empty buffer

一笑奈何 提交于 2020-03-01 19:42:20

问题


I want to read data from a TCP stream but it results in an empty Vec:

extern crate net2;

use net2::TcpBuilder;
use std::io::Read;
use std::io::Write;
use std::io::BufReader;

let tcp = TcpBuilder::new_v4().unwrap();
let mut stream = tcp.connect("127.0.0.1:3306").unwrap();
let mut buf = Vec::with_capacity(1024);
stream.read(&mut buf);    
println!("{:?}", buf); // prints []

When I use stream.read_to_end the buffer is filled but this takes way too long.

In Python I can do something like

import socket 

TCP_IP = '127.0.0.1'
TCP_PORT = 3306
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
#s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close() 
print "received data:", data

How can I achieve this in Rust?


回答1:


The two methods you tried don't work for different reasons:

  • read(): "does not provide any guarantees about whether it blocks waiting for data". In general, read() is unreliable from a users perspective and should only be used as a building block for higher level functions, like read_to_end().

    But maybe more importantly, you have a bug in your code: you create your vector via with_capacity() which reserves memory internally, but doesn't change the length of the vector. It is still empty! When you now slice it like &buf, you pass an empty slice to read(), thus read() cannot read any actual data. To fix that, the elements of your vector need to be initialized: let mut buf = vec![0; 1024] or something like that.

  • read_to_end(): calls read() repeatedly until EOF is encountered. This doesn't really make sense in most TCP stream situations.

So what should you use instead? In your Python code you read a specific number of bytes into a buffer. You can do that in Rust, too: read_exact(). It works like this:

const BUFFER_SIZE: usize = 1024;

let mut stream = ...;
let mut buf = [0; BUFFER_SIZE];
stream.read_exact(&mut buf);

println!("{:?}", buf);

You could also use take(). That way you can use read_to_end():

const BUFFER_SIZE: usize = 1024;

let mut stream = ...;
let mut buf = Vec::with_capacity(BUFFER_SIZE);
stream.take(BUFFER_SIZE).read_to_end(&mut buf);

println!("{:?}", buf);

If you want to use the stream multiple times, you probably want to use by_ref() before calling take().

The two code snippets are not equivalent though! Please read the documentation for more details.



来源:https://stackoverflow.com/questions/46500747/reading-from-tcpstream-results-in-empty-buffer

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!