Awesome
<section class="dex_guide"><h1 class="dex_title">Wangle</h1><section class="dex_document"><h1></h1><p class="dex_introduction">C++ networking library</p><p>Wangle is a library that makes it easy to build protocols, application clients, and application servers.</p> <p>It's like Netty + Finagle smooshed together, but in C++</p>Building and Installing
The main dependencies are:
- The folly library from https://github.com/facebook/folly
- The fizz library from https://github.com/facebookincubator/fizz
- CMake
- OpenSSL, at least version 1.0.2+, preferably with TLS extension support.
Once folly is installed, run the following inside the wangle directory to build, test, and install wangle:
cmake .
make
ctest
sudo make install
Tutorial
There is a tutorial here that explains the basics of Wangle and shows how to build an echo server/client.
Examples
See the examples/ directory for some example Wangle servers and clients
License
Wangle is Apache 2.0-licensed.
Contributing
See the CONTRIBUTING file for how to help out.
Documentation
<p>Wangle interfaces are asynchronous. Interfaces are currently based on <a href="https://github.com/facebook/folly/tree/master/folly/futures">Futures</a>, but we're also exploring how to support fibers</p> <h2 id="client-server-abstractio">Client / Server abstraction <a href="#client-server-abstractio" class="headerLink">#</a></h2> <p>You're probably familiar with Java's Netty, or Python's twisted, or similar libraries.</p> <p>It is built on top of folly/async/io, so it's one level up the stack from that (or similar abstractions like boost::asio)</p> <p>ServerBootstrap - easily manage creation of threadpools and pipelines</p> <p>ClientBootstrap - the same for clients</p> <p>Pipeline - set up a series of handlers that modify your socket data</p> <h2 id="request-response-abstrac">Request / Response abstraction <a href="#request-response-abstrac" class="headerLink">#</a></h2> <p>This is roughly equivalent to the <a href="https://twitter.github.io/finagle/" target="_blank">Finagle</a> library.</p> <p>Aims to provide easy testing, load balancing, client pooling, retry logic, etc. for any request/response type service - i.e. thrift, http, etc.</p> <p>Service - a matched interface between client/server. A server will implement this interface, and a client will call in to it. These are protocol-specific</p> <p>ServiceFilter - a generic filter on a service. Examples: stats, request timeouts, rate limiting</p> <p>ServiceFactory - A factory that creates client connections. Any protocol specific setup code goes here</p> <p>ServiceFactoryFilter - Generic filters that control how connections are created. Client examples: load balancing, pooling, idle timeouts, markdowns, etc.</p></section><section class="dex_document"><h1>ServerBootstrap</h1><p class="dex_introduction">Easily create a new server</p><p>ServerBootstrap does the work to set up one or multiple acceptor threads, and one or multiple sets of IO threads. The thread pools can be the same. SO_REUSEPORT is automatically supported for multiple accept threads. tcp is most common, although udp is also supported.</p> <h2 id="methods">Methods <a href="#methods" class="headerLink">#</a></h2> <p><strong>childPipeline(PipelineFactory<Pipeline>)</strong></p> <p>Sets the pipeline factory for each new connection. One pipeline per connection will be created.</p> <p><strong>group(IOThreadPoolExecutor accept, IOThreadPoolExecutor io)</strong></p> <p>Sets the thread pools for accept and io thread pools. If more than one thread is in the accept group, SO_REUSEPORT is used. Defaults to a single accept thread, and one io thread per core.</p> <p><strong>bind(SocketAddress),bind(port)</strong></p> <p>Binds to a port. Automatically starts to accept after bind.</p> <p><strong>stop()</strong></p> <p>Stops listening on all sockets.</p> <p><strong>join()</strong></p> <p>Joins all threadpools - all current reads and writes will be completed before this method returns.</p> <div class="remarkup-note"><span class="remarkup-note-word">NOTE:</span> however that both accept and io thread pools will be stopped using this method, so the thread pools can't be shared, or care must be taken using shared pools during shutdown.</div> <p><strong>waitForStop()</strong></p> <p>Waits for stop() to be called from another thread.</p> <h2 id="other-methods">Other methods <a href="#other-methods" class="headerLink">#</a></h2> <p><strong>channelFactory(ServerSocketFactory)</strong></p> <p>Sets up the type of server. Defaults to TCP AsyncServerSocket, but AsyncUDPServerSocket is also supported to receive udp messages. In practice, ServerBootstrap is only useful for udp if you need to multiplex the messages across many threads, or have TCP connections going on at the same time, etc. Simple usages of AsyncUDPSocket probably don't need the complexity of ServerBootstrap.</p> <p><strong>pipeline(PipelineFactory<AcceptPipeline>)</strong></p> <p>This pipeline method is used to get the accepted socket (or udp message) <strong>before</strong> it has been handed off to an IO thread. This can be used to steer the accept thread to a particular thread, or for logging.</p> <p>See also AcceptRoutingHandler and RoutingDataHandler for additional help in reading data off of the accepted socket <strong>before</strong> it gets attached to an IO thread. These can be used to hash incoming sockets to specific threads.</p> <p><strong>childHandler(AcceptorFactory)</strong></p> <p>Previously facebook had lots of code that used AcceptorFactories instead of Pipelines, this is a method to support this code and be backwards compatible. The AcceptorFactory is responsible for creating acceptors, setting up pipelines, setting up AsyncSocket read callbacks, etc.</p> <h2 id="examples">Examples <a href="#examples" class="headerLink">#</a></h2> <p>A simple example:</p> <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">ServerBootstrap</span><span class="o"><</span><span class="no">TelnetPipeline</span><span class="o">></span> <span class="no">server</span><span class="o">;</span> <span class="no">server</span><span class="o">.</span><span class="nf" data-symbol-name="childPipeline">childPipeline</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="make_shared">make_shared</span><span class="o"><</span><span class="no">TelnetPipelineFactory</span><span class="o">>());</span> <span class="no">server</span><span class="o">.</span><span class="nf" data-symbol-name="bind">bind</span><span class="o">(</span><span class="no">FLAGS_port</span><span class="o">);</span> <span class="no">server</span><span class="o">.</span><span class="nf" data-symbol-name="waitForStop">waitForStop</span><span class="o">();</span></pre></div></section><section class="dex_document"><h1>ClientBootstrap</h1><p class="dex_introduction">Create clients easily</p><p>ClientBootstrap is a thin wrapper around AsyncSocket that provides a future interface to the connect callback, and a Pipeline interface to the read callback.</p> <h2 id="methods">Methods <a href="#methods" class="headerLink">#</a></h2> <p><strong>group(IOThreadPoolExecutor)</strong></p> <p>Sets the thread or group of threads where the IO will take place. Callbacks are also made on this thread.</p> <p><strong>bind(port)</strong></p> <p>Optionally bind to a specific port</p> <p><strong>Future<Pipeline*> connect(SocketAddress)</strong></p> <p>Connect to the selected address. When the future is complete, the initialized pipeline will be returned.</p> <div class="remarkup-note"><span class="remarkup-note-word">NOTE:</span> future.cancel() can be called to cancel an outstanding connection attempt.</div> <p><strong>pipelineFactory(PipelineFactory<Pipeline>)</strong></p> <p>Set the pipeline factory to use after a connection is successful.</p> <h2 id="example">Example <a href="#example" class="headerLink">#</a></h2> <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">ClientBootstrap</span><span class="o"><</span><span class="no">TelnetPipeline</span><span class="o">></span> <span class="no">client</span><span class="o">;</span> <span class="no">client</span><span class="o">.</span><span class="nf" data-symbol-name="group">group</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="make_shared">make_shared</span><span class="o"><</span><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="wangle">wangle</span><span class="o">::</span><span class="na" data-symbol-name="IOThreadPoolExecutor">IOThreadPoolExecutor</span><span class="o">>(</span><span class="mi">1</span><span class="o">));</span> <span class="no">client</span><span class="o">.</span><span class="nf" data-symbol-name="pipelineFactory">pipelineFactory</span><span class="o">(</span><span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="make_shared">make_shared</span><span class="o"><</span><span class="no">TelnetPipelineFactory</span><span class="o">>());</span> <span class="c">// synchronously wait for the connect to finish</span> <span class="no">auto</span> <span class="no">pipeline</span> <span class="o">=</span> <span class="no">client</span><span class="o">.</span><span class="nf" data-symbol-name="connect">connect</span><span class="o">(</span><span class="nf" data-symbol-name="SocketAddress">SocketAddress</span><span class="o">(</span><span class="no">FLAGS_host</span><span class="o">,</span><span class="no">FLAGS_port</span><span class="o">)).</span><span class="nf" data-symbol-name="get">get</span><span class="o">();</span><span class="c">// close the pipeline when finished</span> <span class="no">pipeline</span><span class="o">-></span><span class="na" data-symbol-name="close">close</span><span class="o">();</span></pre></div></section><section class="dex_document"><h1>Pipeline</h1><p class="dex_introduction">Send your socket data through a series of tubes</p><p>A Pipeline is a series of Handlers that intercept inbound or outbound events, giving full control over how events are handled. Handlers can be added dynamically to the pipeline.</p>
<p>When events are called, a Context* object is passed to the Handler - this means state can be stored in the context object, and a single instantiation of any individual Handler can be used for the entire program.</p> <p>Netty's documentation: <a href="http://netty.io/4.0/api/io/netty/channel/ChannelPipeline.html" target="_blank">ChannelHandler</a></p> <p>Usually, the bottom of the Pipeline is a wangle::AsyncSocketHandler to read/write to a socket, but this isn't a requirement.</p> <p>A pipeline is templated on the input and output types:</p> <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="no">EventBase</span> <span class="no">base_</span><span class="o">;</span> <span class="no">Pipeline</span><span class="o"><</span><span class="no">IOBufQueue</span><span class="o">&,</span> <span class="nc" data-symbol-name="std">std</span><span class="o">::</span><span class="na" data-symbol-context="std" data-symbol-name="unique_ptr">unique_ptr</span><span class="o"><</span><span class="no">IOBuf</span><span class="o">>></span> <span class="no">pipeline</span><span class="o">;</span> <span class="no">pipeline</span><span class="o">.</span><span class="nf" data-symbol-name="addBack">addBack</span><span class="o">(</span><span class="nf" data-symbol-name="AsyncSocketHandler">AsyncSocketHandler</span><span class="o">(</span><span class="nc" data-symbol-name="AsyncSocket">AsyncSocket</span><span class="o">::</span><span class="nf" data-symbol-context="AsyncSocket" data-symbol-name="newSocket">newSocket</span><span class="o">(</span><span class="no">eventBase</span><span class="o">)));</span></pre></div> <p>The above creates a pipeline and adds a single AsyncSocket handler, that will push read events through the pipeline when the socket gets bytes. Let's try handling some socket events:</p> <div class="remarkup-code-block" data-code-lang="php"><pre class="remarkup-code"><span class="k">class</span> <span class="no">MyHandler</span> <span class="o">:</span> <span class="k">public</span> <span class="no">InboundHandler</span><span class="o"><</span><span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="IOBufQueue">IOBufQueue</span><span class="o">&></span> <span class="o">{</span> <span class="k">public</span><span class="o">:</span><span class="no">void</span> <span class="nf" data-symbol-name="read">read</span><span class="o">(</span><span class="no">Context</span><span class="o">*</span> <span class="no">ctx</span><span class="o">,</span> <span class="nc" data-symbol-name="folly">folly</span><span class="o">::</span><span class="na" data-symbol-context="folly" data-symbol-name="IOBufQueue">IOBufQueue</span><span class="o">&</span> <span class="no">q</span><span class="o">)</span> <span class="no">override</span> <span class="o">{</span>
<span class="no">IOBufQueue</span> <span class="no">data</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="no">q</span><span class="o">.</span><span class="nf" data-symbol-name="chainLength">chainLength</span><span class="o">()</span> <span class="o">>=</span> <span class="mi">4</span><span class="o">)</span> <span class="o">{</span>
<span class="no">data</span><span class="o">.</span><span class="nf" data-symbol-name="append">append</span><span class="o">(</span><span class="no">q</span><span class="o">.</span><span class="nf" data-symbol-name="split">split</span><span class="o">(</span><span class="mi">4</span><span class="o">));</span>
<span class="no">ctx</span><span class="o">-></span><span class="na" data-symbol-name="fireRead">fireRead</span><span class="o">(</span><span class="no">data</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">};</span></pre></div>