mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-28 01:01:34 +00:00
Merge pull request #52 from tomaka/multistream-select-doc
Documentation for multistream-select
This commit is contained in:
92
multistream-select/README.md
Normal file
92
multistream-select/README.md
Normal file
@ -0,0 +1,92 @@
|
||||
# Multistream-select
|
||||
|
||||
This crate implements the `multistream-select` protocol, which is the protocol used by libp2p
|
||||
to negotiate which protocol to use with the remote.
|
||||
|
||||
> **Note**: This crate is used by the internals of *libp2p*, and it is not required to
|
||||
> understand it in order to use *libp2p*.
|
||||
|
||||
Whenever a new connection or a new multiplexed substream is opened, libp2p uses
|
||||
`multistream-select` to negotiate with the remote which protocol to use. After a protocol has
|
||||
been successfully negotiated, the stream (ie. the connection or the multiplexed substream)
|
||||
immediately stops using `multistream-select` and starts using the negotiated protocol.
|
||||
|
||||
## Protocol explanation
|
||||
|
||||
The dialer has two options available: either request the list of protocols that the listener
|
||||
supports, or suggest a protocol. If a protocol is suggested, the listener can either accept (by
|
||||
answering with the same protocol name) or refuse the choice (by answering "not available").
|
||||
|
||||
## Examples
|
||||
|
||||
For a dialer:
|
||||
|
||||
```rust
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate multistream_select;
|
||||
extern crate tokio_core;
|
||||
|
||||
use bytes::Bytes;
|
||||
use multistream_select::dialer_select_proto;
|
||||
use futures::{Future, Sink, Stream};
|
||||
use tokio_core::net::TcpStream;
|
||||
use tokio_core::reactor::Core;
|
||||
|
||||
let mut core = Core::new().unwrap();
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum MyProto { Echo, Hello }
|
||||
|
||||
let client = TcpStream::connect(&"127.0.0.1:10333".parse().unwrap(), &core.handle())
|
||||
.from_err()
|
||||
.and_then(move |connec| {
|
||||
let protos = vec![
|
||||
(Bytes::from("/echo/1.0.0"), <Bytes as PartialEq>::eq, MyProto::Echo),
|
||||
(Bytes::from("/hello/2.5.0"), <Bytes as PartialEq>::eq, MyProto::Hello),
|
||||
]
|
||||
.into_iter();
|
||||
dialer_select_proto(connec, protos).map(|r| r.0)
|
||||
});
|
||||
|
||||
let negotiated_protocol: MyProto = core.run(client).expect("failed to find a protocol");
|
||||
println!("negotiated: {:?}", negotiated_protocol);
|
||||
```
|
||||
|
||||
For a listener:
|
||||
|
||||
```rust
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
extern crate multistream_select;
|
||||
extern crate tokio_core;
|
||||
|
||||
use bytes::Bytes;
|
||||
use multistream_select::listener_select_proto;
|
||||
use futures::{Future, Sink, Stream};
|
||||
use tokio_core::net::TcpListener;
|
||||
use tokio_core::reactor::Core;
|
||||
|
||||
let mut core = Core::new().unwrap();
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum MyProto { Echo, Hello }
|
||||
|
||||
let server = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap()
|
||||
.incoming()
|
||||
.from_err()
|
||||
.and_then(move |(connec, _)| {
|
||||
let protos = vec![
|
||||
(Bytes::from("/echo/1.0.0"), <Bytes as PartialEq>::eq, MyProto::Echo),
|
||||
(Bytes::from("/hello/2.5.0"), <Bytes as PartialEq>::eq, MyProto::Hello),
|
||||
]
|
||||
.into_iter();
|
||||
listener_select_proto(connec, protos)
|
||||
})
|
||||
.for_each(|(proto, _connec)| {
|
||||
println!("new remote with {:?} negotiated", proto);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
core.run(server).expect("failed to run server");
|
||||
```
|
@ -18,20 +18,105 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// TODO: use this once stable ; for now we just copy-paste the content of the README.md
|
||||
//#![doc(include = "../README.md")]
|
||||
|
||||
//! # Multistream-select
|
||||
//!
|
||||
//! Multistream-select is the "main" protocol of libp2p.
|
||||
//! Whenever a connection opens between two peers, it starts talking in `multistream-select`.
|
||||
//! This crate implements the `multistream-select` protocol, which is the protocol used by libp2p
|
||||
//! to negotiate which protocol to use with the remote.
|
||||
//!
|
||||
//! The purpose of `multistream-select` is to choose which protocol we are going to use. As soon as
|
||||
//! both sides agree on a given protocol, the socket immediately starts using it and multistream is
|
||||
//! no longer relevant.
|
||||
//! > **Note**: This crate is used by the internals of *libp2p*, and it is not required to
|
||||
//! > understand it in order to use *libp2p*.
|
||||
//!
|
||||
//! However note that `multistream-select` is also sometimes used on top of another protocol such
|
||||
//! as secio or multiplex. For example, two hosts can use `multistream-select` to decide to use
|
||||
//! secio, then use `multistream-select` again (wrapped inside `secio`) to decide to use
|
||||
//! `multiplex`, then use `multistream-select` one more time (wrapped inside `secio` and
|
||||
//! `multiplex`) to decide to use the final actual protocol.
|
||||
//! Whenever a new connection or a new multiplexed substream is opened, libp2p uses
|
||||
//! `multistream-select` to negotiate with the remote which protocol to use. After a protocol has
|
||||
//! been successfully negotiated, the stream (ie. the connection or the multiplexed substream)
|
||||
//! immediately stops using `multistream-select` and starts using the negotiated protocol.
|
||||
//!
|
||||
//! ## Protocol explanation
|
||||
//!
|
||||
//! The dialer has two options available: either request the list of protocols that the listener
|
||||
//! supports, or suggest a protocol. If a protocol is suggested, the listener can either accept (by
|
||||
//! answering with the same protocol name) or refuse the choice (by answering "not available").
|
||||
//!
|
||||
//! ## Examples
|
||||
//!
|
||||
//! For a dialer:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! extern crate bytes;
|
||||
//! extern crate futures;
|
||||
//! extern crate multistream_select;
|
||||
//! extern crate tokio_core;
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! use bytes::Bytes;
|
||||
//! use multistream_select::dialer_select_proto;
|
||||
//! use futures::{Future, Sink, Stream};
|
||||
//! use tokio_core::net::TcpStream;
|
||||
//! use tokio_core::reactor::Core;
|
||||
//!
|
||||
//! let mut core = Core::new().unwrap();
|
||||
//!
|
||||
//! #[derive(Debug, Copy, Clone)]
|
||||
//! enum MyProto { Echo, Hello }
|
||||
//!
|
||||
//! let client = TcpStream::connect(&"127.0.0.1:10333".parse().unwrap(), &core.handle())
|
||||
//! .from_err()
|
||||
//! .and_then(move |connec| {
|
||||
//! let protos = vec![
|
||||
//! (Bytes::from("/echo/1.0.0"), <Bytes as PartialEq>::eq, MyProto::Echo),
|
||||
//! (Bytes::from("/hello/2.5.0"), <Bytes as PartialEq>::eq, MyProto::Hello),
|
||||
//! ]
|
||||
//! .into_iter();
|
||||
//! dialer_select_proto(connec, protos).map(|r| r.0)
|
||||
//! });
|
||||
//!
|
||||
//! let negotiated_protocol: MyProto = core.run(client).expect("failed to find a protocol");
|
||||
//! println!("negotiated: {:?}", negotiated_protocol);
|
||||
//! # }
|
||||
//! ```
|
||||
//!
|
||||
//! For a listener:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! extern crate bytes;
|
||||
//! extern crate futures;
|
||||
//! extern crate multistream_select;
|
||||
//! extern crate tokio_core;
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! use bytes::Bytes;
|
||||
//! use multistream_select::listener_select_proto;
|
||||
//! use futures::{Future, Sink, Stream};
|
||||
//! use tokio_core::net::TcpListener;
|
||||
//! use tokio_core::reactor::Core;
|
||||
//!
|
||||
//! let mut core = Core::new().unwrap();
|
||||
//!
|
||||
//! #[derive(Debug, Copy, Clone)]
|
||||
//! enum MyProto { Echo, Hello }
|
||||
//!
|
||||
//! let server = TcpListener::bind(&"127.0.0.1:0".parse().unwrap(), &core.handle()).unwrap()
|
||||
//! .incoming()
|
||||
//! .from_err()
|
||||
//! .and_then(move |(connec, _)| {
|
||||
//! let protos = vec![
|
||||
//! (Bytes::from("/echo/1.0.0"), <Bytes as PartialEq>::eq, MyProto::Echo),
|
||||
//! (Bytes::from("/hello/2.5.0"), <Bytes as PartialEq>::eq, MyProto::Hello),
|
||||
//! ]
|
||||
//! .into_iter();
|
||||
//! listener_select_proto(connec, protos)
|
||||
//! })
|
||||
//! .for_each(|(proto, _connec)| {
|
||||
//! println!("new remote with {:?} negotiated", proto);
|
||||
//! Ok(())
|
||||
//! });
|
||||
//!
|
||||
//! core.run(server).expect("failed to run server");
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
extern crate bytes;
|
||||
extern crate futures;
|
||||
|
Reference in New Issue
Block a user