簡體   English   中英

非阻塞 TCP socket 使用 socket2 連接失敗

[英]Non-blocking TCP socket fails to connect using socket2

我目前正在使用sockets2 crate 將我的一些代碼從阻塞轉換為非阻塞,但是我在連接套接字時遇到了問題。 在超過超時之前,套接字總是無法連接。 盡管我嘗試搜索示例,但我還沒有找到任何 Rust 代碼顯示如何創建非阻塞 TCP stream。

為了讓您了解我正在嘗試做什么,我當前正在轉換的代碼看起來大致如下。 這沒有給我帶來任何問題並且工作正常,但是為每個套接字創建一個新線程的成本太高了。

let address = SocketAddr::from(([x, y, z, v], port));
let mut socket = TcpStream::connect_timeout(&address, timeout)?;

目前,我連接套接字的代碼如下所示。 由於connect_timeout只能在阻塞模式下執行,所以我使用connect代替,並定期輪詢套接字以檢查它是否已連接。 目前,我在調用connect時不斷收到WouldBlock錯誤,但我不知道這是什么意思。 起初我假設連接正在進行,但立即返回結果將需要阻塞,因此會給出一個WouldBlock錯誤。 但是,由於連接套接字的問題,我第二次猜測這些假設。

let address = SocketAddr::from(([x, y, z, v], port));

// Create socket equivalent to TcpStream
let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))?;

// Enable non-blocking mode on the socket
socket.set_nonblocking(true)?;

// What response should I expect? Do I need to bind an address first?
match socket.connect(&address.into()) {
    Ok(_) => {}
    Err(e) if e.kind() == ErrorKind::WouldBlock => {
        // I keep getting this error, but I don't know what this means.
        // Is non-blocking connect unavailable?
        // Do I need to keep trying to connect until it succeeds?
    },
    // Are there any other types of errors I should be looking for before failing the connection?
    Err(e) => return Err(e),
}

我也不確定確定套接字是否連接的正確方法是什么。 目前,我嘗試讀取零長度緩沖區並檢查是否收到NotConnected錯誤。 但是,我不確定WouldBlock在這種情況下意味着什么,並且我從未從這種方法中得到積極的回應。

let mut buffer = [0u8; 0];

// I also tried self.socket.peer_addr(), but ran into issues where it returned a positive
// response despite not being connected.
match self.socket.read(&mut buffer) {
    Ok(_) => Ok(true),
    // What does WouldBlock mean in this context?
    Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(false),
    Err(e) if e.kind() == ErrorKind::NotConnected => Ok(false),
    Err(e) => Err(e),
}

定期檢查每個套接字,直到達到任意超時以確定它是否已連接。 到目前為止,在連接到已知良好的服務器時,沒有套接字在達到超時(20 秒)之前通過連接。 這些測試都是在 Windows 上的單線程應用程序中使用已知良好的服務器執行的,該服務器已經過檢查可以與我的程序的阻塞版本一起使用。

編輯:這是此問題的最小可重現示例。 但是,由於網絡限制,如果您在 Rust 操場上運行它可能無法正常工作。 https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=a08c22574a971c0032fd9dd37e10fd94

為了讓您了解我正在嘗試做什么,我當前正在轉換的代碼看起來大致如下。 這沒有給我帶來任何問題並且工作正常,但是為每個套接字創建一個新線程的成本太高了。

在我看來,這聽起來很像一個 XY 問題。

我認為您誤解了“非阻塞”的含義。 並不意味着您可以簡單而無需擔心地並行運行多個 sockets。 它的意思是每個會阻塞的操作都會返回一個錯誤,您必須稍后重試。

實際的非阻塞 sockets 通常不會在最終用戶級別使用。 它們適用於依賴它們的庫,並為異步提供一些更高級別的接口。 非阻塞 sockets 很難做到正確。 它們需要與事件配對,否則你只能用 100% cpu 飢餓的繁忙循環來實現它們,這很可能不是你想要的。

不過有好消息嗎? 記住我談到的高級庫在內部使用非阻塞 sockets 現在最著名的一個叫做tokio ,它完全可以滿足您的需求。 它需要你學習一種叫做asynchronism的編程機制,但你會掌握它,我敢肯定:)

我推薦閱讀: https://tokio.rs/tokio/tutorial

當在后台成功啟動非阻塞connect() (或其他操作)時, WouldBlock是預期的錯誤。 然后,您可以等待操作完成所需的超時間隔(使用select()epoll()或其他特定於平台的通知來檢測這一點)。 如果超時,關閉套接字並相應地處理超時。 否則,檢查套接字的SO_ERROR選項以查看操作是成功還是失敗,並采取相應措施。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM