359 lines
No EOL
24 KiB
HTML
359 lines
No EOL
24 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="rustdoc">
|
||
<meta name="description" content="API documentation for the Rust `tokio_proto` crate.">
|
||
<meta name="keywords" content="rust, rustlang, rust-lang, tokio_proto">
|
||
|
||
<title>tokio_proto - Rust</title>
|
||
|
||
<link rel="stylesheet" type="text/css" href="../normalize.css">
|
||
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
|
||
|
||
<link rel="stylesheet" type="text/css" href="../dark.css">
|
||
<link rel="stylesheet" type="text/css" href="../main.css" id="themeStyle">
|
||
<script src="../storage.js"></script>
|
||
|
||
|
||
|
||
|
||
</head>
|
||
<body class="rustdoc mod">
|
||
<!--[if lte IE 8]>
|
||
<div class="warning">
|
||
This old browser is unsupported and will most likely display funky
|
||
things.
|
||
</div>
|
||
<![endif]-->
|
||
|
||
|
||
|
||
<nav class="sidebar">
|
||
<div class="sidebar-menu">☰</div>
|
||
|
||
<p class='location'>Crate tokio_proto</p><div class="sidebar-elems"><div class="block items"><ul><li><a href="#modules">Modules</a></li><li><a href="#structs">Structs</a></li><li><a href="#traits">Traits</a></li></ul></div><p class='location'></p><script>window.sidebarCurrent = {name: 'tokio_proto', ty: 'mod', relpath: '../'};</script></div>
|
||
</nav>
|
||
|
||
<div class="theme-picker">
|
||
<button id="theme-picker" aria-label="Pick another theme!">
|
||
<img src="../brush.svg" width="18" alt="Pick another theme!">
|
||
</button>
|
||
<div id="theme-choices"></div>
|
||
</div>
|
||
<script src="../theme.js"></script>
|
||
<nav class="sub">
|
||
<form class="search-form js-only">
|
||
<div class="search-container">
|
||
<input class="search-input" name="search"
|
||
autocomplete="off"
|
||
placeholder="Click or press ‘S’ to search, ‘?’ for more options…"
|
||
type="search">
|
||
</div>
|
||
</form>
|
||
</nav>
|
||
|
||
<section id='main' class="content">
|
||
<h1 class='fqn'><span class='in-band'>Crate <a class="mod" href=''>tokio_proto</a></span><span class='out-of-band'><span id='render-detail'>
|
||
<a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
|
||
[<span class='inner'>−</span>]
|
||
</a>
|
||
</span><a class='srclink' href='../src/tokio_proto/lib.rs.html#1-280' title='goto source code'>[src]</a></span></h1>
|
||
<div class='docblock'><p>This library provides a toolkit for rapid protocol development and usage,
|
||
working with the rest of the Tokio stack.</p>
|
||
<p>You can find extensive documentation and tutorials in addition to this
|
||
documentation at <a href="https://tokio.rs">https://tokio.rs</a></p>
|
||
<h1 id="protocols" class="section-header"><a href="#protocols">Protocols</a></h1>
|
||
<p>Here, a <strong>protocol</strong> is a way of providing or consuming a service. Protocols
|
||
are implemented via traits, which are arranged into a taxonomy:</p>
|
||
<ul>
|
||
<li><code>pipeline::{ClientProto, ServerProto}</code></li>
|
||
<li><code>multiplex::{ClientProto, ServerProto}</code></li>
|
||
<li><code>streaming::pipeline::{ClientProto, ServerProto}</code></li>
|
||
<li><code>streaming::multiplex::{ClientProto, ServerProto}</code></li>
|
||
</ul>
|
||
<h3 id="pipeline-vs-multiplex" class="section-header"><a href="#pipeline-vs-multiplex">Pipeline vs multiplex</a></h3>
|
||
<p>By default, protocols allow a client to transmit multiple requests without
|
||
waiting for the corresponding responses, which is commonly used to improve
|
||
the throughput of single connections.</p>
|
||
<p>In a <strong>pipelined protocol</strong>, the server responds to client requests in the
|
||
order they were sent. Example pipelined protocols include HTTP/1.1 and Redis.
|
||
Pipelining with the max number of in-flight requests set to 1 implies that
|
||
for each request, the response must be received before sending another
|
||
request on the same connection.</p>
|
||
<p>In a <strong>multiplexed protocol</strong>, the server responds to client requests in the
|
||
order of completion. Request IDs are used to match responses back to requests.</p>
|
||
<p>In both cases, if multiple requests are sent, the service running on the
|
||
server <em>may</em> process them concurrently, although many services will impose
|
||
some restrictions depending on the request type.</p>
|
||
<h3 id="streaming" class="section-header"><a href="#streaming">Streaming</a></h3>
|
||
<p>In a non-streaming protocols, the client sends a complete request in a
|
||
single message, and the server provides a complete response in a single
|
||
message. Protocol tools in this style are available in the top-level <code>pipeline</code>
|
||
and <code>multiplex</code> modules.</p>
|
||
<p>In a <strong>streaming protocol</strong>, requests and responses can carry <strong>body
|
||
streams</strong>, which allows partial processing before the complete body has been
|
||
transferred. Streaming protocol tools are found within the <code>streaming</code>
|
||
submodule.</p>
|
||
<h1 id="transports" class="section-header"><a href="#transports">Transports</a></h1>
|
||
<p>A key part of any protocol is its <strong>transport</strong>, which is the way that it
|
||
sends and receives <em>frames</em> on its connection. For simple protocols, these
|
||
frames correspond directly to complete requests and responses. For more
|
||
complicated protocols, they carry additional metadata, and may only be one
|
||
part of a request or response body.</p>
|
||
<p>Transports are defined by implementing the <code>transport::Transport</code> trait. The
|
||
<code>transport::CodecTransport</code> type can be used to wrap a <code>Codec</code> (from
|
||
<code>tokio-core</code>), which is a simple way to build a transport.</p>
|
||
<h1 id="an-example-server" class="section-header"><a href="#an-example-server">An example server</a></h1>
|
||
<p>The following code shows how to implement a simple server that receives
|
||
newline-separated integer values, doubles them, and returns them. It
|
||
illustrates several aspects of the Tokio stack:</p>
|
||
<ul>
|
||
<li>Implementing a codec <code>IntCodec</code> for reading and writing integers from a
|
||
byte buffer.</li>
|
||
<li>Implementing a server protocol <code>IntProto</code> using this codec as a transport.</li>
|
||
<li>Implementing a service <code>Doubler</code> for doubling integers.</li>
|
||
<li>Spinning up this service on a local port (in <code>main</code>).</li>
|
||
</ul>
|
||
|
||
<pre class="rust rust-example-rendered">
|
||
<span class="kw">extern</span> <span class="kw">crate</span> <span class="ident">futures</span>;
|
||
<span class="kw">extern</span> <span class="kw">crate</span> <span class="ident">tokio_core</span>;
|
||
<span class="kw">extern</span> <span class="kw">crate</span> <span class="ident">tokio_proto</span>;
|
||
<span class="kw">extern</span> <span class="kw">crate</span> <span class="ident">tokio_service</span>;
|
||
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">str</span>;
|
||
<span class="kw">use</span> <span class="ident">std</span>::<span class="ident">io</span>::{<span class="self">self</span>, <span class="ident">ErrorKind</span>, <span class="ident">Write</span>};
|
||
|
||
<span class="kw">use</span> <span class="ident">futures</span>::{<span class="ident">future</span>, <span class="ident">Future</span>, <span class="ident">BoxFuture</span>};
|
||
<span class="kw">use</span> <span class="ident">tokio_core</span>::<span class="ident">io</span>::{<span class="ident">Io</span>, <span class="ident">Codec</span>, <span class="ident">Framed</span>, <span class="ident">EasyBuf</span>};
|
||
<span class="kw">use</span> <span class="ident">tokio_proto</span>::<span class="ident">TcpServer</span>;
|
||
<span class="kw">use</span> <span class="ident">tokio_proto</span>::<span class="ident">pipeline</span>::<span class="ident">ServerProto</span>;
|
||
<span class="kw">use</span> <span class="ident">tokio_service</span>::<span class="ident">Service</span>;
|
||
|
||
<span class="comment">// First, we implement a *codec*, which provides a way of encoding and</span>
|
||
<span class="comment">// decoding messages for the protocol. See the documentation for `Codec` in</span>
|
||
<span class="comment">// `tokio-core` for more details on how that works.</span>
|
||
|
||
<span class="attribute">#[<span class="ident">derive</span>(<span class="ident">Default</span>)]</span>
|
||
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">IntCodec</span>;
|
||
|
||
<span class="kw">fn</span> <span class="ident">parse_u64</span>(<span class="ident">from</span>: <span class="kw-2">&</span>[<span class="ident">u8</span>]) <span class="op">-></span> <span class="prelude-ty">Result</span><span class="op"><</span><span class="ident">u64</span>, <span class="ident">io</span>::<span class="ident">Error</span><span class="op">></span> {
|
||
<span class="prelude-val">Ok</span>(<span class="ident">str</span>::<span class="ident">from_utf8</span>(<span class="ident">from</span>)
|
||
.<span class="ident">map_err</span>(<span class="op">|</span><span class="ident">e</span><span class="op">|</span> <span class="ident">io</span>::<span class="ident">Error</span>::<span class="ident">new</span>(<span class="ident">ErrorKind</span>::<span class="ident">InvalidData</span>, <span class="ident">e</span>))<span class="question-mark">?</span>
|
||
.<span class="ident">parse</span>()
|
||
.<span class="ident">map_err</span>(<span class="op">|</span><span class="ident">e</span><span class="op">|</span> <span class="ident">io</span>::<span class="ident">Error</span>::<span class="ident">new</span>(<span class="ident">ErrorKind</span>::<span class="ident">InvalidData</span>, <span class="ident">e</span>))<span class="question-mark">?</span>)
|
||
}
|
||
|
||
<span class="kw">impl</span> <span class="ident">Codec</span> <span class="kw">for</span> <span class="ident">IntCodec</span> {
|
||
<span class="kw">type</span> <span class="ident">In</span> <span class="op">=</span> <span class="ident">u64</span>;
|
||
<span class="kw">type</span> <span class="ident">Out</span> <span class="op">=</span> <span class="ident">u64</span>;
|
||
|
||
<span class="comment">// Attempt to decode a message from the given buffer if a complete</span>
|
||
<span class="comment">// message is available; returns `Ok(None)` if the buffer does not yet</span>
|
||
<span class="comment">// hold a complete message.</span>
|
||
<span class="kw">fn</span> <span class="ident">decode</span>(<span class="kw-2">&</span><span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">buf</span>: <span class="kw-2">&</span><span class="kw-2">mut</span> <span class="ident">EasyBuf</span>) <span class="op">-></span> <span class="prelude-ty">Result</span><span class="op"><</span><span class="prelude-ty">Option</span><span class="op"><</span><span class="ident">u64</span><span class="op">></span>, <span class="ident">io</span>::<span class="ident">Error</span><span class="op">></span> {
|
||
<span class="kw">if</span> <span class="kw">let</span> <span class="prelude-val">Some</span>(<span class="ident">i</span>) <span class="op">=</span> <span class="ident">buf</span>.<span class="ident">as_slice</span>().<span class="ident">iter</span>().<span class="ident">position</span>(<span class="op">|</span><span class="kw-2">&</span><span class="ident">b</span><span class="op">|</span> <span class="ident">b</span> <span class="op">==</span> <span class="string">b'\n'</span>) {
|
||
<span class="comment">// remove the line, including the '\n', from the buffer</span>
|
||
<span class="kw">let</span> <span class="ident">full_line</span> <span class="op">=</span> <span class="ident">buf</span>.<span class="ident">drain_to</span>(<span class="ident">i</span> <span class="op">+</span> <span class="number">1</span>);
|
||
|
||
<span class="comment">// strip the'`\n'</span>
|
||
<span class="kw">let</span> <span class="ident">slice</span> <span class="op">=</span> <span class="kw-2">&</span><span class="ident">full_line</span>.<span class="ident">as_slice</span>()[..<span class="ident">i</span>];
|
||
|
||
<span class="prelude-val">Ok</span>(<span class="prelude-val">Some</span>(<span class="ident">parse_u64</span>(<span class="ident">slice</span>)<span class="question-mark">?</span>))
|
||
} <span class="kw">else</span> {
|
||
<span class="prelude-val">Ok</span>(<span class="prelude-val">None</span>)
|
||
}
|
||
}
|
||
|
||
<span class="comment">// Attempt to decode a message assuming that the given buffer contains</span>
|
||
<span class="comment">// *all* remaining input data.</span>
|
||
<span class="kw">fn</span> <span class="ident">decode_eof</span>(<span class="kw-2">&</span><span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">buf</span>: <span class="kw-2">&</span><span class="kw-2">mut</span> <span class="ident">EasyBuf</span>) <span class="op">-></span> <span class="ident">io</span>::<span class="prelude-ty">Result</span><span class="op"><</span><span class="ident">u64</span><span class="op">></span> {
|
||
<span class="kw">let</span> <span class="ident">amt</span> <span class="op">=</span> <span class="ident">buf</span>.<span class="ident">len</span>();
|
||
<span class="prelude-val">Ok</span>(<span class="ident">parse_u64</span>(<span class="ident">buf</span>.<span class="ident">drain_to</span>(<span class="ident">amt</span>).<span class="ident">as_slice</span>())<span class="question-mark">?</span>)
|
||
}
|
||
|
||
<span class="kw">fn</span> <span class="ident">encode</span>(<span class="kw-2">&</span><span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">item</span>: <span class="ident">u64</span>, <span class="ident">into</span>: <span class="kw-2">&</span><span class="kw-2">mut</span> <span class="ident">Vec</span><span class="op"><</span><span class="ident">u8</span><span class="op">></span>) <span class="op">-></span> <span class="ident">io</span>::<span class="prelude-ty">Result</span><span class="op"><</span>()<span class="op">></span> {
|
||
<span class="macro">writeln</span><span class="macro">!</span>(<span class="ident">into</span>, <span class="string">"{}"</span>, <span class="ident">item</span>);
|
||
<span class="prelude-val">Ok</span>(())
|
||
}
|
||
}
|
||
|
||
<span class="comment">// Next, we implement the server protocol, which just hooks up the codec above.</span>
|
||
|
||
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">IntProto</span>;
|
||
|
||
<span class="kw">impl</span><span class="op"><</span><span class="ident">T</span>: <span class="ident">Io</span> <span class="op">+</span> <span class="lifetime">'static</span><span class="op">></span> <span class="ident">ServerProto</span><span class="op"><</span><span class="ident">T</span><span class="op">></span> <span class="kw">for</span> <span class="ident">IntProto</span> {
|
||
<span class="kw">type</span> <span class="ident">Request</span> <span class="op">=</span> <span class="ident">u64</span>;
|
||
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">u64</span>;
|
||
<span class="kw">type</span> <span class="ident">Transport</span> <span class="op">=</span> <span class="ident">Framed</span><span class="op"><</span><span class="ident">T</span>, <span class="ident">IntCodec</span><span class="op">></span>;
|
||
<span class="kw">type</span> <span class="ident">BindTransport</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op"><</span><span class="self">Self</span>::<span class="ident">Transport</span>, <span class="ident">io</span>::<span class="ident">Error</span><span class="op">></span>;
|
||
|
||
<span class="kw">fn</span> <span class="ident">bind_transport</span>(<span class="kw-2">&</span><span class="self">self</span>, <span class="ident">io</span>: <span class="ident">T</span>) <span class="op">-></span> <span class="self">Self</span>::<span class="ident">BindTransport</span> {
|
||
<span class="prelude-val">Ok</span>(<span class="ident">io</span>.<span class="ident">framed</span>(<span class="ident">IntCodec</span>))
|
||
}
|
||
}
|
||
|
||
<span class="comment">// Now we implement a service we'd like to run on top of this protocol</span>
|
||
|
||
<span class="kw">pub</span> <span class="kw">struct</span> <span class="ident">Doubler</span>;
|
||
|
||
<span class="kw">impl</span> <span class="ident">Service</span> <span class="kw">for</span> <span class="ident">Doubler</span> {
|
||
<span class="kw">type</span> <span class="ident">Request</span> <span class="op">=</span> <span class="ident">u64</span>;
|
||
<span class="kw">type</span> <span class="ident">Response</span> <span class="op">=</span> <span class="ident">u64</span>;
|
||
<span class="kw">type</span> <span class="ident">Error</span> <span class="op">=</span> <span class="ident">io</span>::<span class="ident">Error</span>;
|
||
<span class="kw">type</span> <span class="ident">Future</span> <span class="op">=</span> <span class="ident">BoxFuture</span><span class="op"><</span><span class="ident">u64</span>, <span class="ident">io</span>::<span class="ident">Error</span><span class="op">></span>;
|
||
|
||
<span class="kw">fn</span> <span class="ident">call</span>(<span class="kw-2">&</span><span class="self">self</span>, <span class="ident">req</span>: <span class="ident">u64</span>) <span class="op">-></span> <span class="self">Self</span>::<span class="ident">Future</span> {
|
||
<span class="comment">// Just return the request, doubled</span>
|
||
<span class="ident">future</span>::<span class="ident">finished</span>(<span class="ident">req</span> <span class="op">*</span> <span class="number">2</span>).<span class="ident">boxed</span>()
|
||
}
|
||
}
|
||
|
||
<span class="comment">// Finally, we can actually host this service locally!</span>
|
||
<span class="kw">fn</span> <span class="ident">main</span>() {
|
||
<span class="kw">let</span> <span class="ident">addr</span> <span class="op">=</span> <span class="string">"0.0.0.0:12345"</span>.<span class="ident">parse</span>().<span class="ident">unwrap</span>();
|
||
<span class="ident">TcpServer</span>::<span class="ident">new</span>(<span class="ident">IntProto</span>, <span class="ident">addr</span>)
|
||
.<span class="ident">serve</span>(<span class="op">||</span> <span class="prelude-val">Ok</span>(<span class="ident">Doubler</span>));
|
||
}</pre>
|
||
</div><h2 id='modules' class='section-header'><a href="#modules">Modules</a></h2>
|
||
<table>
|
||
<tr class=' module-item'>
|
||
<td><a class="mod" href="multiplex/index.html"
|
||
title='mod tokio_proto::multiplex'>multiplex</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Multiplexed RPC protocols.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="mod" href="pipeline/index.html"
|
||
title='mod tokio_proto::pipeline'>pipeline</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Pipelined RPC protocols.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="mod" href="streaming/index.html"
|
||
title='mod tokio_proto::streaming'>streaming</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Streaming protocols.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="mod" href="util/index.html"
|
||
title='mod tokio_proto::util'>util</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Utilities for building protocols</p>
|
||
|
||
</td>
|
||
</tr></table><h2 id='structs' class='section-header'><a href="#structs">Structs</a></h2>
|
||
<table>
|
||
<tr class=' module-item'>
|
||
<td><a class="struct" href="struct.Connect.html"
|
||
title='struct tokio_proto::Connect'>Connect</a></td>
|
||
<td class='docblock-short'>
|
||
<p>A future for establishing a client connection.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="struct" href="struct.TcpClient.html"
|
||
title='struct tokio_proto::TcpClient'>TcpClient</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Builds client connections to external services.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="struct" href="struct.TcpServer.html"
|
||
title='struct tokio_proto::TcpServer'>TcpServer</a></td>
|
||
<td class='docblock-short'>
|
||
<p>A builder for TCP servers.</p>
|
||
|
||
</td>
|
||
</tr></table><h2 id='traits' class='section-header'><a href="#traits">Traits</a></h2>
|
||
<table>
|
||
<tr class=' module-item'>
|
||
<td><a class="trait" href="trait.BindClient.html"
|
||
title='trait tokio_proto::BindClient'>BindClient</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Binds an I/O object as a client of a service.</p>
|
||
|
||
</td>
|
||
</tr>
|
||
<tr class=' module-item'>
|
||
<td><a class="trait" href="trait.BindServer.html"
|
||
title='trait tokio_proto::BindServer'>BindServer</a></td>
|
||
<td class='docblock-short'>
|
||
<p>Binds a service to an I/O object.</p>
|
||
|
||
</td>
|
||
</tr></table></section>
|
||
<section id='search' class="content hidden"></section>
|
||
|
||
<section class="footer"></section>
|
||
|
||
<aside id="help" class="hidden">
|
||
<div>
|
||
<h1 class="hidden">Help</h1>
|
||
|
||
<div class="shortcuts">
|
||
<h2>Keyboard Shortcuts</h2>
|
||
|
||
<dl>
|
||
<dt><kbd>?</kbd></dt>
|
||
<dd>Show this help dialog</dd>
|
||
<dt><kbd>S</kbd></dt>
|
||
<dd>Focus the search field</dd>
|
||
<dt><kbd>↑</kbd></dt>
|
||
<dd>Move up in search results</dd>
|
||
<dt><kbd>↓</kbd></dt>
|
||
<dd>Move down in search results</dd>
|
||
<dt><kbd>↹</kbd></dt>
|
||
<dd>Switch tab</dd>
|
||
<dt><kbd>⏎</kbd></dt>
|
||
<dd>Go to active search result</dd>
|
||
<dt><kbd>+</kbd></dt>
|
||
<dd>Expand all sections</dd>
|
||
<dt><kbd>-</kbd></dt>
|
||
<dd>Collapse all sections</dd>
|
||
</dl>
|
||
</div>
|
||
|
||
<div class="infos">
|
||
<h2>Search Tricks</h2>
|
||
|
||
<p>
|
||
Prefix searches with a type followed by a colon (e.g.
|
||
<code>fn:</code>) to restrict the search to a given type.
|
||
</p>
|
||
|
||
<p>
|
||
Accepted types are: <code>fn</code>, <code>mod</code>,
|
||
<code>struct</code>, <code>enum</code>,
|
||
<code>trait</code>, <code>type</code>, <code>macro</code>,
|
||
and <code>const</code>.
|
||
</p>
|
||
|
||
<p>
|
||
Search functions by type signature (e.g.
|
||
<code>vec -> usize</code> or <code>* -> vec</code>)
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
|
||
|
||
<script>
|
||
window.rootPath = "../";
|
||
window.currentCrate = "tokio_proto";
|
||
</script>
|
||
<script src="../main.js"></script>
|
||
<script defer src="../search-index.js"></script>
|
||
</body>
|
||
</html> |