【发布时间】:2017-03-07 02:52:46
【问题描述】:
我正在尝试使用由openssl::ssl::SslStream(来自crates.io)包裹的TcpStream 与服务器通信的客户端程序。它应该等待read,如果收到没有延迟,则处理从服务器发送的数据。同时,它应该能够不管读取向服务器发送消息。
我尝试了一些方法,例如
- 将单个流传递给读取和写入线程。
read和write方法都需要可变引用,因此我无法将单个流传递给两个线程。 - 我关注了In Rust how do I handle parallel read writes on a TcpStream,但是
TcpStream似乎没有clone方法,SslStream也没有。 - 我尝试使用
as_raw_fd和from_raw_fd复制TcpStream:
fn irc_read(mut stream: SslStream<TcpStream>) {
loop {
let mut buf = vec![0; 2048];
let resp = stream.ssl_read(&mut buf);
match resp {
// Process Message
}
}
}
fn irc_write(mut stream: SslStream<TcpStream>) {
thread::sleep(Duration::new(3, 0));
let msg = "QUIT\n";
let res = stream.ssl_write(msg.as_bytes());
let _ = stream.flush();
match res {
// Process
}
}
fn main() {
let ctx = SslContext::new(SslMethod::Sslv23).unwrap();
let read_ssl = Ssl::new(&ctx).unwrap();
let write_ssl = Ssl::new(&ctx).unwrap();
let raw_stream = TcpStream::connect((SERVER, PORT)).unwrap();
let mut fd_stream: TcpStream;
unsafe {
fd_stream = TcpStream::from_raw_fd(raw_stream.as_raw_fd());
}
let mut read_stream = SslStream::connect(read_ssl, raw_stream).unwrap();
let mut write_stream = SslStream::connect(write_ssl, fd_stream).unwrap();
let read_thread = thread::spawn(move || {
irc_read(read_stream);
});
let write_thread = thread::spawn(move || {
irc_write(write_stream);
});
let _ = read_thread.join();
let _ = write_thread.join();
}
此代码可以编译,但在第二个 SslStream::connect 出现恐慌
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Failure(Ssl(ErrorStack([Error { library: "SSL routines", function: "SSL23_GET_SERVER_HELLO", reason: "unknown protocol" }])))', ../src/libcore/result.rs:788
stack backtrace:
1: 0x556d719c6069 - std::sys::backtrace::tracing::imp::write::h00e948915d1e4c72
2: 0x556d719c9d3c - std::panicking::default_hook::_{{closure}}::h7b8a142818383fb8
3: 0x556d719c8f89 - std::panicking::default_hook::h41cf296f654245d7
4: 0x556d719c9678 - std::panicking::rust_panic_with_hook::h4cbd7ca63ce1aee9
5: 0x556d719c94d2 - std::panicking::begin_panic::h93672d0313d5e8e9
6: 0x556d719c9440 - std::panicking::begin_panic_fmt::hd0daa02942245d81
7: 0x556d719c93c1 - rust_begin_unwind
8: 0x556d719ffcbf - core::panicking::panic_fmt::hbfc935564d134c1b
9: 0x556d71899f02 - core::result::unwrap_failed::h66f79b2edc69ddfd
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/obj/../src/libcore/result.rs:29
10: 0x556d718952cb - _<core..result..Result<T, E>>::unwrap::h49a140af593bc4fa
at /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/obj/../src/libcore/result.rs:726
11: 0x556d718a5e3d - dbrust::main::h24a50e631826915e
at /home/lastone817/dbrust/src/main.rs:87
12: 0x556d719d1826 - __rust_maybe_catch_panic
13: 0x556d719c8702 - std::rt::lang_start::h53bf99b0829cc03c
14: 0x556d718a6b83 - main
15: 0x7f40a0b5082f - __libc_start_main
16: 0x556d7188d038 - _start
17: 0x0 - <unknown>
error: Process didn't exit successfully: `target/debug/dbrust` (exit code: 101)
到目前为止,我发现的最佳解决方案是使用非阻塞。我在流上使用Mutex 并将其传递给两个线程。然后读取线程获取锁并调用read。如果没有消息,它会释放锁,以便写入线程可以使用流。使用这种方法,读取线程确实忙于等待,导致 100% 的 CPU 消耗。我认为这不是最好的解决方案。
有没有一种安全的方法来分离流的读取和写入方面?
【问题讨论】:
-
您能否展示重现您的担忧的代码?没有它,我们很难提供帮助。
-
为了补充@E_net4 的观点,请向我们展示您尝试了什么,否则我们可能会复制所有已经“全部失败”的“可能方式”。
-
另外,标准库中没有
SslStream。你必须创建一个minimal reproducible example;我们不会搜索每一个板条箱以找到可能是您的意思的SslStream。 -
感谢 cmets。我已经为我的情况添加了详细信息。
-
"但是
TcpStream似乎没有clone方法" — 只需在TcpStream文档中搜索“克隆”,您就会找到 @ 987654324@。这能回答你的问题吗?
标签: multithreading ssl tcp concurrency rust