如何设置TcpStream上的连接超时

如何设置TcpStream上的连接超时,tcp,rust,Tcp,Rust,我正在尝试使用以下代码连接到无法访问的服务器: println!("Connecting"); TcpStream::connect(s).unwrap(); println!("Connected"); 当我运行代码时,它会卡在第二行 输出: Connecting 目前无法更改建立TCP连接时的超时。网络堆栈将有自己的默认设置,这些设置可能因操作系统而异;我认为一分钟是典型的超时。没有简单、标准的方法可以做到这一点,所以我通过使用移植到Rust实现了这一点,只做了一个小小的更改:一旦建立了

我正在尝试使用以下代码连接到无法访问的服务器:

println!("Connecting");
TcpStream::connect(s).unwrap();
println!("Connected");
当我运行代码时,它会卡在第二行

输出:

Connecting

目前无法更改建立TCP连接时的超时。网络堆栈将有自己的默认设置,这些设置可能因操作系统而异;我认为一分钟是典型的超时。

没有简单、标准的方法可以做到这一点,所以我通过使用移植到Rust实现了这一点,只做了一个小小的更改:一旦建立了连接,将套接字设置回阻塞状态,以便可以与Rust的std I/O一起使用,当然,将它包装回一个
std::net::TcpStream

以下是回购协议:

从src/lib.rs:

pub fn tcp_connect_with_timeout(socket_addr: std::net::SocketAddr, timeout: Duration) -> Result<TcpStream, ConnectionError> {
  // Create a socket file descriptor.
  let socket_fd = try!(nix::sys::socket::socket(
    nix::sys::socket::AddressFamily::Inet,
    nix::sys::socket::SockType::Stream,
    nix::sys::socket::SockFlag::empty()
  ));

  // Set the socket to non-blocking mode so we can `select()` on it.
  try!(nix::fcntl::fcntl(
    socket_fd,
    nix::fcntl::FcntlArg::F_SETFL(nix::fcntl::O_NONBLOCK)
  ));

  let connection_result = nix::sys::socket::connect(
    socket_fd,
    &(nix::sys::socket::SockAddr::Inet(nix::sys::socket::InetAddr::from_std(&socket_addr)))
  );

  match connection_result {
    Ok(_) => (),
    Err(e) => {
      match e {
        nix::Error::Sys(errno) => {
          match errno {
            nix::errno::Errno::EINPROGRESS => (), // socket is non-blocking so an EINPROGRESS is to be expected
            _ => return Err(ConnectionError::from(e))
          }
        }
        nix::Error::InvalidPath => unreachable!() //
      }
    }
  }

  let mut timeout_timeval = nix::sys::time::TimeVal {
    tv_sec: timeout.as_secs() as i64,
    tv_usec: timeout.subsec_nanos() as i32
  };

  // Create a new fd_set monitoring our socket file descriptor.
  let mut fdset = nix::sys::select::FdSet::new();
  fdset.insert(socket_fd);

  // `select()` on it, will return when the connection succeeds or times out.
  let select_res = try!(nix::sys::select::select(
    socket_fd + 1,
    None,
    Some(&mut fdset),
    None,
    &mut timeout_timeval
  ));

  // This it what fails if `addr` is unreachable.
  if select_res != 1 {
    println!("select return value: {}", select_res);
    return Err(ConnectionError::SelectError);
  }

  // Make sure the socket encountered no error.
  let socket_error_code = try!(nix::sys::socket::getsockopt(
    socket_fd,
    nix::sys::socket::sockopt::SocketError
  ));

  if socket_error_code != 0 {
    return Err(ConnectionError::SocketError(socket_error_code));
  }

  // Set the socket back to blocking mode so it can be used with std's I/O facilities.
  try!(nix::fcntl::fcntl(
    socket_fd,
    nix::fcntl::FcntlArg::F_SETFL(nix::fcntl::OFlag::empty())
  ));

  // Wrap it in a TcpStream and return that stream.
  Ok(
    unsafe { TcpStream::from_raw_fd(socket_fd) }
  )
}

如果您将异步rust与tokio一起使用,则可以使用:-

const CONNECTION_TIME: u64 = 100;

...

let (socket, _response) = match tokio::time::timeout(
     Duration::from_secs(CONNECTION_TIME),
     tokio::net::TcpStream::connect("127.0.0.1:8080")
 )
 .await
 {
     Ok(ok) => ok,
     Err(e) => panic!(format!("timeout while connecting to server : {}", e)),
 }
 .expect("Error while connecting to server")
2020年的问候

与此同时,答案改变了, 这不再是“不容易做到”,而是:


不是永远。大约一分钟后就会超时。你可能想修正答案,因为谷歌可能会先阅读这篇文章。见:
const CONNECTION_TIME: u64 = 100;

...

let (socket, _response) = match tokio::time::timeout(
     Duration::from_secs(CONNECTION_TIME),
     tokio::net::TcpStream::connect("127.0.0.1:8080")
 )
 .await
 {
     Ok(ok) => ok,
     Err(e) => panic!(format!("timeout while connecting to server : {}", e)),
 }
 .expect("Error while connecting to server")
TcpStream::connect_timeout()