|
1 | | -//! Local sockets, an IPC primitive featuring a server and multiple clients connecting to that |
2 | | -//! server using a filesystem path or an identifier inside a special namespace, each having a |
3 | | -//! private connection to that server. |
| 1 | +//! Local sockets, a socket-like IPC primitive in which clients access a server through a |
| 2 | +//! filesystem path or an identifier inside a special namespace, with each client having a |
| 3 | +//! private connection to the server. |
4 | 4 | //! |
5 | | -//! ## Implementation types |
6 | | -//! Local sockets are not a real IPC method implemented by the OS – they exist to paper over the |
7 | | -//! differences between the two underlying implementations currently in use: Unix domain sockets and |
8 | | -//! Windows named pipes. |
| 5 | +//! ## Implementations and dispatch |
| 6 | +//! Local sockets are not a real IPC primitive implemented by the OS, but rather a construct of |
| 7 | +//! Interprocess that is implemented in terms of an underlying IPC primitive. Different IPC |
| 8 | +//! primitives are available on different platforms and have different capabilities and |
| 9 | +//! limitations. As such, the types representing local sockets that you can find in this |
| 10 | +//! module – [`Listener`], [`Stream`], [`RecvHalf`], [`SendHalf`] – are really enums in the style |
| 11 | +//! of `enum_dispatch` that contain variants for all the different implementations of local |
| 12 | +//! sockets that are available, and the types that they dispatch between are talked to via the |
| 13 | +//! corresponding [`Listener`](traits::Listener), [`Stream`](traits::Stream) |
| 14 | +//! [`RecvHalf`](traits::RecvHalf), [`SendHalf`](traits::SendHalf) traits that you can find in the |
| 15 | +//! [`traits`] module. (Note that this dispatch is currently zero-cost on all platforms, as there |
| 16 | +//! is only one underlying local socket implementation per platform, with Windows only using named |
| 17 | +//! pipe based local sockets and Unix only using Unix-domain socket based local sockets, but this |
| 18 | +//! may change in the future with the introduction of support for |
| 19 | +//! [the Windows implementation of Unix-domain sockets][udswnd]. Even then, the overhead of this |
| 20 | +//! dispatch is insignificant compared to the overhead of making the system calls that perform |
| 21 | +//! the actual communication.) |
9 | 22 | //! |
10 | | -//! Interprocess defines [traits] that implementations of local sockets implement, and enums that |
11 | | -//! constitute devirtualized trait objects (not unlike those provided by the `enum_dispatch` crate) |
12 | | -//! for those traits. The implementation used, in cases where multiple options apply, is chosen at |
13 | | -//! construction via the [name](Name) and [name type](NameType) infrastructure. |
| 23 | +//! [udswnd]: https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ |
14 | 24 | //! |
15 | | -//! ## Differences from regular sockets |
16 | | -//! A few missing features, primarily on Windows, require local sockets to omit some important |
17 | | -//! functionality, because code relying on it wouldn't be portable. Some notable differences are: |
18 | | -//! - No `.shutdown()` – your communication protocol must manually negotiate end of transmission. |
19 | | -//! Notably, `.read_to_string()` and `.read_all()` will always block indefinitely at some point. |
20 | | -//! - No datagram sockets – the difference in semantics between connectionless datagram Unix-domain |
21 | | -//! sockets and connection-based named message pipes on Windows does not allow bridging those two |
22 | | -//! into a common API. You can emulate datagrams on top of streams anyway, so no big deal, right? |
| 25 | +//! The [`prelude`] module is there to make it easier to handle all of this complexity without |
| 26 | +//! suffering from naming collisions. **`use interprocess::local_socket::prelude::*;` is the |
| 27 | +//! recommended way of bringing local sockets into scope.** |
| 28 | +//! |
| 29 | +//! ## Stability |
| 30 | +//! Since interprocess communication cannot happen without agreement on a protocol between two or |
| 31 | +//! more processes, the mapping of local sockets to underlying primitives is stable and |
| 32 | +//! predictable. **The IPC primitive selected depends only on the current platform and the |
| 33 | +//! [name type](NameType) used.** The mapping is trivial unless noted otherwise (in particular, |
| 34 | +//! Interprocess never inserts its own message framing or any other type of metadata into the |
| 35 | +//! stream – the bytes you write are the exact bytes that come out the other end), which means |
| 36 | +//! that the portable API of local sockets is suitable for communicating with programs that do |
| 37 | +//! not use Interprocess themselves, including programs not written in Rust. All you need to do |
| 38 | +//! is use the correct name type for every platform. |
| 39 | +//! |
| 40 | +//! ## Raw handle and file descriptor access |
| 41 | +//! The enum dispatchers purposely omit implementations of `{As,Into,From}Raw{Handle,Fd}`, |
| 42 | +//! `As{Handle,Fd}`, `From<Owned{HandleFd}>` and `Into<Owned{Handle,Fd}>`. To access those trait |
| 43 | +//! implementations on the underlying implementation types, you need to match on the enum. For |
| 44 | +//! instance: |
| 45 | +//! ```no_run |
| 46 | +//! # #[cfg(unix)] |
| 47 | +//! use {interprocess::local_socket::prelude::*, std::os::unix::prelude::*}; |
| 48 | +//! # #[cfg(unix)] fn hi(fd: OwnedFd, fd2: OwnedFd) { |
| 49 | +//! |
| 50 | +//! // Creating a stream from a file descriptor |
| 51 | +//! let stream = LocalSocketStream::UdSocket(fd.into()); |
| 52 | +//! # let _ = stream; |
| 53 | +//! |
| 54 | +//! // Consuming a stream to get its file descriptor |
| 55 | +//! let fd = match stream { |
| 56 | +//! LocalSocketStream::UdSocket(s) => OwnedFd::from(s), |
| 57 | +//! }; |
| 58 | +//! # let _ = fd; |
| 59 | +//! |
| 60 | +//! # let stream = LocalSocketStream::UdSocket(fd2.into()); |
| 61 | +//! // Accessing a stream's file descriptor without taking ownership |
| 62 | +//! let fd = match stream { |
| 63 | +//! LocalSocketStream::UdSocket(s) => s.as_fd(), |
| 64 | +//! }; |
| 65 | +//! # let _ = fd; |
| 66 | +//! |
| 67 | +//! // Listener, RecvHalf, and SendHalf work analogously. |
| 68 | +//! // Works just the same on Windows under the replacement of Fd with Handle. |
| 69 | +//! # } |
| 70 | +//! ``` |
23 | 71 |
|
24 | 72 | #[macro_use] |
25 | 73 | mod enumdef; |
|
0 commit comments