Hi again everyone, here comes another Rust lang series episode. In last episode we've built simple TCP server and used web browser and command line application curl to connect it. Now we are going to implement our own simple TCP client to connect this server.
Simple TCP client
I hope that your TCP Server from the last episode is still running. If not, please start it again. Now we can implement this code and see a response from the server.
use std::io::prelude::*;
use std::net::TcpStream;
fn main() {
let ip_and_port = "127.0.0.1:1234";
let mut stream = TcpStream::connect(ip_and_port).unwrap();
let mut vec = vec![];
let ret = stream.read_to_end(&mut vec);
let str = std::str::from_utf8(&vec).unwrap();
println!("Received data in bytes{:?}", vec);
println!("Data in text: {}", str);
}
Breaking down
We utilized API known from std::net we've also used in the previous episode for building a TCP server. Let's mention some new methods.
connect() method of TcpStream creates a connection to given IP and port address and return TCP stream.
read_to_end is a handy method for loading all data from TCP stream into vector.
From String episode we already know how to get string from utf8 bytes. That could use that but now we will use similar function from_utf8 which takes reference of the vector and returns Result containing &str.
Output
If everything works fine, we should receive data from server like this:
Received data in bytes[72, 105, 32, 116, 111, 32, 97, 108, 108, 32, 83, 116, 101, 101, 109, 105, 116, 101, 114, 115, 33, 13, 10]
Data in text: Hi to all Steemiters!
Improved error handling
As usually, we should improve error handling a bit as we don't want our application crashed somewhere in the middle and we also desire to know what has happened in some human friendly way.
use std::io::prelude::*;
use std::net::TcpStream;
fn main() {
let ip_and_port = "127.0.0.1:1234";
let mut stream_res = TcpStream::connect(ip_and_port);
if let Ok(mut stream) = stream_res {
let mut vec = vec![];
let read_res = stream.read_to_end(&mut vec);
if let Ok(bytes) = read_res {
let from_res = std::str::from_utf8(&vec);
if let Ok(str) = from_res {
println!("Received data {} bytes{:?}", bytes, vec);
println!("Data in text: {}", str);
} else if let Err(err) = from_res {
println ! ("Error while converting to string - {}", err);
}
}
} else if let Err(err) = stream_res {
println!("Cannot connect - {}", err.to_string());
}
println!("Application finished!");
}
Breaking down
What can happen here? Various things can happen here - either connection can be refused or timeouted, or stream data can be broken and string conversion can fail or something overflow, who knows what it will be bue we should be ready for that. Like this, we can handle each problem and so the application will not panic prematurely. You can stop your server, run a client again and check such a scenario.
Error output
Cannot connect - Connection refused (os error 111)
Application finished!
Coll! The application finished correctly with reporting expected connection issue. Task done for today!
Postfix
That's all for now, thank you for your appreciations, feel free to comment and point out possible mistakes (first 24 hours works the best but any time is fine). May Jesus bless your programming skills, use them wisely and see you next time.
Meanwhile, you can also check the official documentation for additional related information: