【问题标题】:rust non blocking openssl streamrust 非阻塞 openssl 流
【发布时间】:2020-02-16 04:02:24
【问题描述】:

尝试创建非阻塞 ssl 流:

use openssl::ssl::{SslMethod, SslConnector};
use std::io::{Read, Write};
use std::net::TcpStream;

let connector = SslConnector::builder(SslMethod::tls()).unwrap().build();

let stream = TcpStream::connect("google.com:443").unwrap();
stream.set_nonblocking(true);
let mut stream = connector.connect("google.com", stream).unwrap();

但是我收到了这个错误:

thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value:WouldBlock(MidHandshakeSslStream { stream: SslStream { stream: TcpStream { addr:V4(10.137.0.17:55628), peer: V4(172.217.21.78:443), fd: 3 }, ssl: Ssl { state: "SSLv3/TLSwrite client hello", verify_result: X509VerifyResult { code: 0, error: "ok" } } }, error: Error { code: ErrorCode(2), cause: Some(Io(Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" })) } })', src/libcore/result.rs:1051:5 

如何创建非阻塞 ssl 流?

【问题讨论】:

标签: sockets rust stream openssl nonblocking


【解决方案1】:

tokio 使用它创建的任何套接字都会自动配置为非阻塞。

我建议查看tokio-native-tls 并查看its examples

它依赖于native-tls,这是对特定平台 TLS 实现的抽象。

具体来说,这个 crate 在 Windows 上使用 SChannel(通过 schannel crate), macOS 上的 Secure Transport (通过 security-framework crate), 和所有其他平台上的 OpenSSL(通过 openssl crate)。

除非您有非常具体的用例,否则这可能正是您所需要的。

【讨论】:

    【解决方案2】:

    如果需要非阻塞流但您不想将 tokio 添加为依赖项,则可能的解决方案是:

    use openssl::ssl::{SslMethod, SslConnector};
    use std::io::{Read, Write};
    use std::net::TcpStream;
    
    let connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
    
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = connector.connect("google.com", stream).unwrap();
    let inner_stream = stream.get_ref();
    inner_stream.set_nonblocking(true);
    

    【讨论】:

      【解决方案3】:

      tokio 项目有tokio-openssl crate。您可能需要拥抱整个 async/await 机器并使用该板条箱来执行非阻塞 openssl:

      //# openssl = "0.10.25"
      //# tokio = "0.2.0-alpha.6"
      //# tokio-net = "0.2.0-alpha.6"
      //# tokio-openssl = "0.4.0-alpha.6"
      use openssl::ssl::{SslMethod, SslConnector};
      use tokio::net::TcpStream;
      use tokio::prelude::*;
      use tokio_net::driver::Handle;
      use tokio_openssl::connect;
      use std::error::Error;
      
      #[tokio::main]
      async fn main() -> Result<(), Box<dyn Error>> {
          let sslconf = SslConnector::builder(SslMethod::tls())?
              .build()
              .configure()?;
          // The following 3 lines are equivalent to:
          //     let stream = TcpStream::connect("google.com:443").await?;
          // It's just going to show that the socket is indeed nonblocking.
          let stream = std::net::TcpStream::connect("google.com:443")?;
          stream.set_nonblocking(true)?;
          let stream = TcpStream::from_std(stream, &Handle::default())?;
          let mut stream = connect(sslconf, "google.com", stream).await?;
      
          stream.write_all(b"GET / HTTP/1.0\r\n\r\n").await?;
          let mut res = vec![];
          stream.read_to_end(&mut res).await?;
          dbg!(String::from_utf8_lossy(&res));
      
          Ok(())
      }
      

      当然,这也意味着现在您必须使用 beta/nightly 频道。它可能适合您的项目,也可能不适合。

      【讨论】:

        猜你喜欢
        • 2014-06-07
        • 2011-12-05
        • 2012-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多