2017-09-30 20 views
2

Je veux lire les données à partir d'un flux TCP, mais il en résulte une Vec vide:lecture des résultats TcpStream dans un tampon vide

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 [] 

Lorsque j'utilise stream.read_to_end le tampon est rempli, mais cela prend trop de temps.

En Python, je peux faire quelque chose comme

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 

Comment puis-je parvenir à Rust?

Répondre

4

Les deux méthodes essayées ne fonctionnent pas pour des raisons différentes:

  • read(): « ne fournit aucune garantie quant à savoir si elle bloque l'attente de données ». En général, read() est plutôt peu fiable (du point de vue des utilisateurs) et ne devrait être utilisé que comme un bloc de construction pour les fonctions de niveau supérieur, comme read_to_end().

    Mais peut-être plus important encore, vous avez un bug dans votre code: vous créez votre vecteur via with_capacity() qui réserve de la mémoire en interne, mais ne change pas la longueur du vecteur. C'est encore vide! Lorsque vous le découpez maintenant comme &buf, vous passez une tranche vide à read(), ainsi read() ne peut pas lire de données réelles. Pour résoudre ce problème, les éléments de votre vecteur doivent déjà être initialisés: let mut buf = vec![0; 1024] ou quelque chose comme ça.

  • read_to_end(): appelle read() jusqu'à ce que EOF soit rencontré. Cela n'a pas vraiment de sens dans la plupart des situations de flux TCP.

Alors, que devriez-vous utiliser à la place? Dans votre code python, vous lisez un nombre spécifique d'octets dans un tampon. Bien sûr, vous pouvez le faire dans Rust, aussi: read_exact(). Il fonctionne comme ceci:

const BUFFER_SIZE: usize = 1024; 

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

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

Vous pouvez également utiliser take(). De cette façon, vous pouvez utiliser 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); 

Si vous souhaitez utiliser le flux plusieurs fois, vous voulez probablement utiliser by_ref() avant d'appeler take().

Les deux extraits de code ne sont cependant pas équivalents! Veuillez lire la documentation pour plus de détails.

+0

Nous vous remercions de votre réponse utile au début. Le problème que j'ai - est le même que celui de read_to_end. Cela prend vraiment 3 secondes pour remplir le tampon, où le script python s'exécute en quelques millisecondes. Depuis la rouille est un langage rapide, je crois que je manque quelque chose – xhallix

+0

@xhallix Strange. Dans ce cas, vous devez ajouter plus d'informations à votre question. Votre 'TcpBuilder' ne provient pas de la bibliothèque standard, alors d'où vient-il? –

+0

Il vient de https://github.com/rust-lang-nursery/net2-rs. Mais j'ai le même problème avec le standard TcpStream. Le tcpBuilder me donne en fait le 'std :: net :: TcpStream' btw. Si vous souhaitez, nous pouvons continuer ce chat sur 'gitter' ou ailleurs où - pour éviter de spammer ce fil – xhallix