【问题标题】:How do I set connect timeout on TcpStream如何在 TcpStream 上设置连接超时
【发布时间】:2015-07-13 08:43:56
【问题描述】:

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

println!("Connecting");
TcpStream::connect(s).unwrap();
println!("Connected");

当我运行代码时,它卡在第二行。

输出:

Connecting

【问题讨论】:

  • 不是永远。大约一分钟后它应该会超时。

标签: tcp rust


【解决方案1】:

2020 年的问候。

与此同时,答案发生了变化, 它不再是“不容易做到”,而是:

TcpStream::connect_timeout()

https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.connect_timeout

【讨论】:

    【解决方案2】:

    没有简单的标准方法可以做到这一点,所以我通过使用nix cratethis answer 移植到Rust 来做到这一点,并做了一个小改动:一旦建立连接,将套接字设置回阻塞状态,所以它可以与 Rust 的 std I/O 一起使用,当然也可以将其包装在 std::net::TcpStream 中。

    这里是回购:https://github.com/filsmick/rust-tcp-connection-timeout

    来自 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) }
      )
    }
    

    ConnectionErrorerror.rs 中定义,但如果您愿意,可以通过展开而不是使用try! 来忽略它。

    不过有一个问题:select 在撰写本文时还没有在主要的 nix 存储库中实现,但是有一个 pending Pull Request,所以你必须同时依赖一个 fork(它不过,合并应该不会花很长时间):

    [dependencies]
    nix = { git = "https://github.com/utkarshkukreti/nix-rust.git", branch = "add-sys-select" }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      【解决方案4】:

      如果你在 tokio 中使用 async rust,那么你可以使用这个:-

      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")
      

      【讨论】:

        猜你喜欢
        • 2017-04-17
        • 1970-01-01
        • 1970-01-01
        • 2013-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-09
        • 2018-12-19
        相关资源
        最近更新 更多