mentat/tokio_proto/index.html

359 lines
24 KiB
HTML
Raw Permalink Normal View History

2018-08-22 17:04:13 +00:00
<!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">&#9776;</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'>&#x2212;</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">&amp;</span>[<span class="ident">u8</span>]) <span class="op">-&gt;</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">u64</span>, <span class="ident">io</span>::<span class="ident">Error</span><span class="op">&gt;</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">&amp;</span><span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">buf</span>: <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">EasyBuf</span>) <span class="op">-&gt;</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="prelude-ty">Option</span><span class="op">&lt;</span><span class="ident">u64</span><span class="op">&gt;</span>, <span class="ident">io</span>::<span class="ident">Error</span><span class="op">&gt;</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">&amp;</span><span class="ident">b</span><span class="op">|</span> <span class="ident">b</span> <span class="op">==</span> <span class="string">b&#39;\n&#39;</span>) {
<span class="comment">// remove the line, including the &#39;\n&#39;, 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&#39;`\n&#39;</span>
<span class="kw">let</span> <span class="ident">slice</span> <span class="op">=</span> <span class="kw-2">&amp;</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">&amp;</span><span class="kw-2">mut</span> <span class="self">self</span>, <span class="ident">buf</span>: <span class="kw-2">&amp;</span><span class="kw-2">mut</span> <span class="ident">EasyBuf</span>) <span class="op">-&gt;</span> <span class="ident">io</span>::<span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="ident">u64</span><span class="op">&gt;</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">&amp;</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">&amp;</span><span class="kw-2">mut</span> <span class="ident">Vec</span><span class="op">&lt;</span><span class="ident">u8</span><span class="op">&gt;</span>) <span class="op">-&gt;</span> <span class="ident">io</span>::<span class="prelude-ty">Result</span><span class="op">&lt;</span>()<span class="op">&gt;</span> {
<span class="macro">writeln</span><span class="macro">!</span>(<span class="ident">into</span>, <span class="string">&quot;{}&quot;</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">&lt;</span><span class="ident">T</span>: <span class="ident">Io</span> <span class="op">+</span> <span class="lifetime">&#39;static</span><span class="op">&gt;</span> <span class="ident">ServerProto</span><span class="op">&lt;</span><span class="ident">T</span><span class="op">&gt;</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">&lt;</span><span class="ident">T</span>, <span class="ident">IntCodec</span><span class="op">&gt;</span>;
<span class="kw">type</span> <span class="ident">BindTransport</span> <span class="op">=</span> <span class="prelude-ty">Result</span><span class="op">&lt;</span><span class="self">Self</span>::<span class="ident">Transport</span>, <span class="ident">io</span>::<span class="ident">Error</span><span class="op">&gt;</span>;
<span class="kw">fn</span> <span class="ident">bind_transport</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">io</span>: <span class="ident">T</span>) <span class="op">-&gt;</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&#39;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">&lt;</span><span class="ident">u64</span>, <span class="ident">io</span>::<span class="ident">Error</span><span class="op">&gt;</span>;
<span class="kw">fn</span> <span class="ident">call</span>(<span class="kw-2">&amp;</span><span class="self">self</span>, <span class="ident">req</span>: <span class="ident">u64</span>) <span class="op">-&gt;</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">&quot;0.0.0.0:12345&quot;</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>&#9166;</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>