问题
I have a need to make sure the client side of the TCP connection goes through a particular (IP) interface. The standard way would be to bind()
the socket to the IP:0
, before the connect()
.
I started looking at tokio::net::TcpStream::connect()
and friends, which doesn't seem to have a way to do this. I took a step back and looked at std::net::TcpStream
, which doesn't have it either.
Am I missing something, or do I need to go through some lower level APIs?
回答1:
The best way of doing this at the moment is indeed to use socket2
to create the socket and convert it into a Tokio TcpStream
. In order to correctly handle the fact that the connection step will be blocking with this approach, you can use tokio::task::spawn_blocking.
use std::io::Result;
use tokio::task::spawn_blocking;
use tokio::net::TcpStream;
use socket2::{Socket, SockAddr, Domain, Type};
async fn connect_bind(bind: SockAddr, connect: SockAddr) -> Result<TcpStream> {
spawn_blocking(move || {
let socket = Socket::new(Domain::ipv4(), Type::stream(), None)?;
socket.bind(&bind)?;
socket.connect(&connect)?;
TcpStream::from_std(socket.into_tcp_stream())
}).await?
}
Using spawn_blocking
like this is rather common — this is how Tokio implements file system operations.
来源:https://stackoverflow.com/questions/59298027/how-to-bind-on-tcp-client-side-in-rust-tokio