I have the following source code that should try to connect to a server for 200 seconds. After that time, it should return an error.
use std::{
io::{self, Result, Write},
net::{SocketAddr, TcpStream},
time::Duration,
};
struct Client {
channel: Option<TcpStream>,
}
impl Client {
fn new() -> Self {
Self { channel: None }
}
fn connect(&mut self, addr: SocketAddr, duration: Duration) -> Result<()> {
let connection = TcpStream::connect_timeout(&addr, duration)?;
self.channel = Some(connection);
Ok(())
}
fn send(&mut self, msg: &[u8]) -> Result<()> {
self.channel
.as_mut()
.ok_or(io::Error::new(io::ErrorKind::NotConnected, "Not connected"))?
.write_all(msg)?;
Ok(())
}
}
fn main() {
let mut client = Client::new();
println!("Waiting to connect to server...");
let result_conn = client.connect(
SocketAddr::from(([127, 0, 0, 1], 3030)),
Duration::new(200, 0),
);
if result_conn.is_ok() {
let msg = b"Hi, I am Hernan and this is my first client-server program";
println!("Sending message: {:?}", msg);
match client.send(msg) {
Ok(_) => println!("Message sent"),
Err(e) => println!("Failed to send message: {:?}", e),
}
}
if let Err(e) = result_conn {
println!("Fail to connect: {:?}", e);
}
}
However, when I run the program it immediately returns the error ConnectionRefused
instead of trying to connect for 200 seconds as I expected.
I am running this program on Linux Ubuntu 22.04. Why isn’t connect_timeout()
blocking the execution and retrying the connection for the specified time?
I attach the source code for the server:
use std::{
io::{Read, Result},
net::{SocketAddr, TcpListener, TcpStream},
};
struct Server {
channel: TcpStream,
}
impl Server {
const MAX_BUFF_SIZE: usize = 128;
fn new(addr: SocketAddr) -> Result<Self> {
println!("Waiting for connections...");
let listener = TcpListener::bind(addr)?;
let (stream, socket) = listener.accept()?;
println!("Connection received from {:?}", socket);
Ok(Self { channel: stream })
}
fn recv(&mut self) -> Result<[u8; Self::MAX_BUFF_SIZE]> {
let mut buff = [0; Self::MAX_BUFF_SIZE];
self.channel.read(&mut buff)?;
Ok(buff)
}
}
fn main() -> Result<()> {
let mut server = Server::new(SocketAddr::from(([127, 0, 0, 1], 3030)))?;
let msg = server.recv()?;
println!("Message received: {:?}", msg);
Ok(())
}
8
I have found a workaround for this problem to make it work with the requirements posted in the question (as @SteffenUllrich suggested to retry the connection). The new version for the cliend should be as follows:
use std::{
io::{self, Result, Write},
net::{SocketAddr, TcpStream},
time::{Duration, Instant},
};
struct Client {
channel: Option<TcpStream>,
}
impl Client {
fn new() -> Self {
Self { channel: None }
}
fn connect(&mut self, addr: SocketAddr, timeout: Duration, retry_time: Duration) -> Result<()> {
let start_time = Instant::now();
loop {
match TcpStream::connect(addr) {
Ok(channel) => {
self.channel = Some(channel);
return Ok(());
}
Err(e) => {
let elapsed_time = start_time.elapsed();
if elapsed_time > timeout {
return Err(e);
}
std::thread::sleep(retry_time);
}
}
}
}
fn send(&mut self, msg: &[u8]) -> Result<()> {
self.channel
.as_mut()
.ok_or(io::Error::new(io::ErrorKind::NotConnected, "Not connected"))?
.write_all(msg)?;
Ok(())
}
}
fn main() {
let mut client = Client::new();
println!("Waiting to connect to server...");
let result_conn = client.connect(
SocketAddr::from(([127, 0, 0, 1], 3030)),
Duration::from_secs(200),
Duration::from_millis(300),
);
if result_conn.is_ok() {
let msg = b"Hi, I am Hernan and this is my first client-server program";
println!("Sending message: {:?}", msg);
match client.send(msg) {
Ok(_) => println!("Message sent"),
Err(e) => println!("Failed to send message: {:?}", e),
}
}
if let Err(e) = result_conn {
println!("Fail to connect: {:?}", e);
}
}