-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Amend RFC 517: Add material on std::net #807
Conversation
* The static distinction between `TcpAcceptor` and `TcpListener` has been | ||
removed (more on this in the [socket][Sockets] section). | ||
* The `clone` functionality has been removed in favor of `duplicate` (same | ||
caveats as `TcpStream`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reasoning for not using clone
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Clone
trait primarily indicates that the clone
operation itself is infallible whereas the system call dup
can fail (file descriptor exhaustion). I suspect that WSADuplicateSocket
may also have some similar error conditions.
I had to look in the source code to see that SO_REUSEADDR was being set. It's useful, but should be documented and have an option. Also, SO_REUSEPORT (a newish option for linux/bsd) would be really, really nice to support as an option http://lwn.net/Articles/542629/ I have a threaded server that does concurrent accepts, on the same 'cloned' socket, and I was shocked to run strace and see that TcpListener was 1) creating a pipe 2) calling select() even though no timeout was set (something with close_accept). These were creating a thundering herd problem; select returns 'connection is available' to ALL threads, even though only one will then call accept successfully - the rest will get EAGAIN. If the threads were just calling accept() directly, no thundering herd should happen on new linuxes. So I think this is doing in the right direction, if TcpListener can copy itself using dup(), and accept() with no timeout maps directly to an accept() syscall, without select() messing things up. That should work for 'basic cross platform'. If SO_REUSEPORT was supported, threads (or processes) could just all create their listeners from scratch and not dup anything. I'm trying to use 100% safe code, but I realize stuff like REUSEPORT isn't 100% portable, and you need it to be set before the bind() happens. So us app developers are in a "bind", pun intended... |
Also remove some `&mut self` methods as only `&self` is necessary.
Thanks for the article link! It was a nice read :) I'd definitely love to support this level of configuration, it's certainly been requested multiple times! I think that something like I think for now we may want to avoid these sorts of options or various configuration for creating new sockets. The provided constructors serve as supplying some reasonable defaults, and various other options can be supported through a separate constructor method. I would personally prefer to defer the precise method of what a "highly configurable constructor" would look like due to the need to land these basic implementations somewhat quickly in-tree. Some thoughts I have on this topic, however, are:
Either way I think we definitely have some options for pursuing configuration of opening of each network socket type, but for now we shouldn't be closing any doors by taking the conservative option of only providing one default constructor. This is similar to the story for |
a later date in a more robust fashion with `select`. | ||
* The `accept` function no longer takes `&mut self` and returns `SocketAddr`. | ||
The change in mutability is done to express that multiple `accept` calls can | ||
happen concurrently. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for the concurrent accept. Seems pretty standard, and would work fine for my toy use case at least. EDIT: as long as there's no hidden select() giving you a gun-at-foot thundering herd problem...
It is unclear how socket library initialisation is done on platforms where it is necessary. I.e. on Windows you must call EDIT: this is API RFC, not an implementation one… Ignore my question |
@nagisa that could in theory affect the API actually if we decide to expose explicit setup/teardown functions, although I'm not sure that we would want to do so. I do think it is a bug, however, that we are not calling |
... | ||
} | ||
#[cfg(unix)] impl AsRawFd for TcpListener { ... } | ||
#[cfg(windows)] impl AsRawSocket for TcpListener { ... } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great to be able to create TcpStream
, TcpListener
, and UdpSocket
from an AsRawFd
or AsRawSocket
as well (e.g. file descriptor passing or cross I/O library interface).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that this would be quite useful! I think we may want to develop our story around these raw representations a little more before exploring this area, however. The AsRawFoo
traits are pretty new and I'd want to make sure that they're sufficient before we start adding conversions in the other direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is, however, other interest in this, so we may be able to at least sketch out something #[unstable]
for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! Could you add this as a new amendment of the RFC #517 to follow the discussion please?
Some ideas:
cc rust-lang/rust#14194 (abstract UNIX domain socket) |
@l0kod this at best would be |
Not necessarily if you take ownership. Something like this: |
I have an in-progress implementation PR as well now: rust-lang/rust#22015 The PR specifically fleshes out many details of the |
|
||
Some important points of note are: | ||
|
||
* The `send` and `recv` function take `&self` instead of `&mut self` to indicate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
send_to
and recv_from
?
Relevant rust issue related to the naming of |
fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: &A) -> io::Result<usize>; | ||
fn socket_addr(&self) -> io::Result<SocketAddr>; | ||
fn duplicate(&self) -> io::Result<UdpSocket>; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fwiw, there are useful reasons for calling connect()
on a UDP socket:
a) In many protocols you are exchanging a stream of UDP packets with a single peer, and connect() can simplify your internal API.
b) In some (non-NAT-friendly) protocols (eg: RTP), you need to find a local IP address to tell the other end about. A reasonably common/portable/clean way to do this is to open a UDP socket, connect()
to the peer IP to force the kernel to bind the local end, and then use getsockname()
to fetch the IP address the kernel decided to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree! I believe that this should be done through a future Socket
API though instead of having a large number of constructors on UdpSocket
.
If I may be so bold: By splitting it up into separate TCP client, server and UDP socket objects, I find this proposed API pre-supposes only UDP/TCP types of sockets and that the sockets will be used in particular ways. This places a number of restrictions on the underlying (assuming BSD sockets) API that don't exist at the syscall level. BSD sockets really just has different constructors, and then after that everything is a fd and you call (almost) the same set of syscalls on any socket. That underlying shared syscall structure isn't evident in this proposed API. |
This PR has been belatedly merged (after the actual work had landed); it was left open by mistake. There's not much to debate here, given the very conservative design (and that it is largely just using the existing io traits). The renaming of SocketAddr is likely to land as a follow-up. |
The IO reform RFC is being split into several semi-independent pieces, posted as PRs like this one.
This RFC amendment adds the networking section.
Rendered