Open hawkw opened 4 years ago
It's worth noting that Mio's TcpSocket
already exposes some additional socket options that Tokio doesn't expose:
We may want to expose these as well
Opened tokio-rs/mio#1384 to expose buffer size, and tokio-rs/mio#1385 to expose the keepalive interval. We may also want to add SO_NODELAY...
I think it makes total sense to add these methods to TcpSocket
. :+1:
I ran into a similar difficulty while updating tarssh to Tokio 0.3 - I was setting send/recv buffers on the TcpStream
from an accept()
call, but there seems no way to (sensibly) replicate this behaviour in 0.3?
So how to set TCP keepalive for socket from accept()?
If Tokio does not expose a method for doing it, you can do it with the socket2
crate using something like SockRef
.
Having used these methods from tokio 0.2 — namely set_keepalive
— it would be great to have these in tokio 1.0 as well. For now, I'm using SockRef as @Darksonn mentioned (thanks @Darksonn).
Is there any reasoning why available socket options are not exposed? This kind of scratches Tokio out from some application
is there a better way to set keepalive? The way I'm doing it right now is inelegant.
yeah, i have no idea why setting options is not in the tokio api, but currently this is only option that i am aware of. Basically you have to create external socket structure and hopefully cast it to the tokio's version after setting the correct option.
BIND_DEVICE, please!!!
Two years have passed, any update on this issue please? Noticed that @hawkw 's commit is closed: net: expose keepalive configuration on TcpSocket But it seems no indirect solution provided, I mean, do we have to use non-safe methods?
The socket2
crate can generally set any socket option safely. Other than that, please open a new issue if there is some specific option that you think Tokio should provide.
@Darksonn thanks , following safe code can work:
use socket2::{SockRef, TcpKeepalive};
...
info!("connecting to {addr}");
let tcp = TcpStream::connect(&addr).await?;
info!("tcp connected to {addr}");
let ka = TcpKeepalive::new().with_time(std::time::Duration::from_secs(30));
let sf = SockRef::from(&tcp);
sf.set_tcp_keepalive(&ka)?;
...
@howellzhu's code worked great for me!
Is your feature request related to a problem? Please describe. While updating Hyper to use Tokio 0.3 (hyperium/hyper#2317), it turned out that most of the socket options that Hyper needs to set are no longer available on
TcpStream
or on the newTcpSocket
type. Instead, it was necessary to to open the socket usingsocket2
and usesocket2
to set the socket options, resulting in some fairly unpleasant code for converting betweensocket2::Socket
andTcpSocket
, and then performing an asynchronous connect viaTcpSocket
. It would be nice ifTcpSocket
supported these socket options directly.In particular, it's not great to have to manually convert a socket2
Socket
to a TokioTcpSocket
viaIntoRawFd/FromRawFd
. It's relatively easy for users to mess this up in the following ways:AsRawFd
rather thanIntoRawFd
, failing to transfer ownership of the file descriptor, so that dropping theSocket
closes the file descriptorTcpSocket
. If the socket isn't put in non-blocking mode, using it will block, potentially causing the runtime to silently hang.IntoRawSocket
/FromRawSocket
traits on Windows).Also, it requires unsafe code in downstream crates that would be nice to abstract over.
It would be nice if all of these operations could be performed on
TcpSocket
without having to also usesocket2
. Or, at least, it would be nice if the conversion betweensocket2
andTcpSocket
was less complex.Describe the solution you'd like Ideally,
TcpSocket
would provide the ability to set at least the socket options required by Hyper:My understanding is that adding these options would require an upstream addition in
mio
, which I'm happy to make.Describe alternatives you've considered
Alternatively, we could:
socket2
for setting any socket options other thanSO_REUSEADDR
. I discussed why this is not great above.Rather than adding these additional options on
TcpSocket
, we could add a conversion betweensocket2::Socket
andtokio::net::TcpSocket
that abstracts over the complexities I discussed above. Adding a conversion would hide the unsafe code behind Tokio's API, ensure that the socket is put in non-blocking mode, and ensure that ownership of the file descriptor/Windows SOCKET is transferred.The downside of this is that it would require taking a
socket2
dependency in Tokio, which may not be desirable for stability reasons. A dependency could be feature-flagged, though...From<T: IntoRawFd>
or similar toTcpSocket
that sets O_NONBLOCK etc. This is definitely a bad idea since there is no way to ensure that the file descriptor is actually a TCP socket. Let's not do that.