我已阅读std::net
和mio的文档,我发现了一些方法,例如set_nodelay
和set_keepalive
,但我还没找到一种在给定套接字上设置其他套接字选项的方法,如SO_REUSEPORT
和SO_REUSEADDR
。我怎么能这样做?
答案 0 :(得分:6)
因为SO_REUSEPORT
isn't cross-platform,您需要深入了解特定于平台的代码。在这种情况下,您可以从套接字获取原始文件描述符,然后使用libc crate中的函数,类型和值来设置所需的选项:
extern crate libc; // 0.2.43
use std::{io, mem, net::TcpListener, os::unix::io::AsRawFd};
fn main() -> Result<(), io::Error> {
let listener = TcpListener::bind("0.0.0.0:8888")?;
unsafe {
let optval: libc::c_int = 1;
let ret = libc::setsockopt(
listener.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_REUSEPORT,
&optval as *const _ as *const libc::c_void,
mem::size_of_val(&optval) as libc::socklen_t,
);
if ret != 0 {
return Err(io::Error::last_os_error());
}
}
Ok(())
}
我不能保证这是设置此选项的正确位置,或者我没有在不安全的块中搞砸了某些东西,但它确实在macOS 10.12上编译并运行。
更好的解决方案可能是查看nix crate,它为大多数* nix特定的代码提供了更好的包装器:
extern crate nix; // 0.11.0
use nix::sys::socket::{self, sockopt::ReusePort};
use std::{error::Error, net::TcpListener, os::unix::io::AsRawFd};
fn main() -> Result<(), Box<Error>> {
let listener = TcpListener::bind("0.0.0.0:8888")?;
socket::setsockopt(listener.as_raw_fd(), ReusePort, &true)?;
Ok(())
}
更好的解决方案可能是查看net2 crate,它提供了专门针对网络相关代码的更高级别的方法:
extern crate net2; // 0.2.33
use net2::{unix::UnixTcpBuilderExt, TcpBuilder};
fn main() -> Result<(), std::io::Error> {
let listener = TcpBuilder::new_v4()?
.reuse_address(true)?
.reuse_port(true)?
.bind("0.0.0.0:8888")?
.listen(42)?;
Ok(())
}