Crate tokio_websockets
source ·Expand description
tokio-websockets
High performance, strict, tokio-util based websockets implementation.
Notice
This crate has not been tested enough to an extent that I would deem it ready for usage in production enviroments of big projects. Try it before deploying and please give feedback!
Why use tokio-websockets?
- Built with tokio-util, intended to be used with tokio from the ground up
- Minimal dependencies: The base only requires:
- tokio, tokio-util, bytes, futures-util (which almost all tokio projects depend on)
- fastrand
- SHA1 backend, e.g. sha1_smol (see Feature flags)
- Big selection of features to tailor dependencies to any project (see Feature flags)
- SIMD support: AVX2 or SSE2 for frame (un)masking and accelerated UTF-8 validation
- Strict conformance with the websocket specification, passes the Autobahn test suite without relaxations by default (some can be enabled for performance)
- TLS support
- Reusable TLS connectors
- Uses widely known crates from the ecosystem for types, for example
Uri
fromhttp
in the client - Cheaply clonable messages due to
Bytes
as payload storage - Tuned for performance: no unnecessary duplicate UTF-8 validation, no duplicate bounds checking (this however heavily uses unsafe code, which is sound to my knowledge, if not, open an issue!)
Feature flags
Feature flags in tokio-websockets are added to allow tailoring it to your needs.
simd
will enable AVX2 and SSE2 accelerated masking and UTF-8 validationclient
enables a tiny client implementationserver
enables a tiny server implementationhttp-integration
enables a method forhttp::Request
upgrade generation
TLS support is supported via any of the following feature flags:
native-tls
for atokio-native-tls
backed implementationrustls-webpki-roots
for atokio-rustls
backed implementation withwebpki-roots
rustls-native-roots
for atokio-rustls
backed implementation withrustls-native-certs
One SHA1 implementation is required, usually provided by the TLS implementation:
ring
is used ifrustls
is the TLS library- The
openssl
feature will useopenssl
, usually prefered on most Linux/BSD systems withnative-tls
- The
sha1_smol
feature can be used as a fallback if no TLS is needed
For these reasons, I recommend disabling default features and using a configuration that makes sense for you, for example:
tokio-websockets = { version = "*", default-features = false, features = ["client", "sha1_smol"] }
tokio-websockets = { version = "*", default-features = false, features = ["client", "simd", "rustls-webpki-roots"] }
Example
This is a simple websocket echo server without any proper error handling.
More examples can be found in the examples folder.
use futures_util::SinkExt;
use http::Uri;
use tokio::net::TcpListener;
use tokio_websockets::{ClientBuilder, Error, Message, ServerBuilder};
#[tokio::main]
async fn main() -> Result<(), Error> {
let listener = TcpListener::bind("127.0.0.1:3000").await?;
tokio::spawn(async move {
while let Ok((stream, _)) = listener.accept().await {
let mut ws_stream = ServerBuilder::new()
.accept(stream)
.await?;
tokio::spawn(async move {
// Just an echo server, really
while let Some(Ok(msg)) = ws_stream.next().await {
if msg.is_text() || msg.is_binary() {
ws_stream.send(msg).await?;
}
}
Ok::<_, Error>(())
});
}
Ok::<_, Error>(())
});
let uri = Uri::from_static("ws://127.0.0.1:3000");
let mut client = ClientBuilder::from_uri(uri).connect().await?;
client.send(Message::text(String::from("Hello world!"))).await?;
while let Some(Ok(msg)) = client.next().await {
if let Ok(text) = msg.as_text() {
assert_eq!(text, "Hello world!");
// We got one message, just stop now
client.close(None, None).await?;
}
}
Ok(())
}
Caveats / Limitations / ToDo
Currently, WebsocketStream
does not implement Stream
due to the poll_next
nature of the trait, which makes implementing it with actual async code near impossible.
I am waiting for async traits and will implement it once possible. Until then, a method called next
already exists and serves as a replacement for futures-util’s next
, which most users were probably looking for.
Further, websocket compression is currently unsupported.
Re-exports
pub use client::Builder as ClientBuilder;
pub use error::Error;
pub use proto::CloseCode;
pub use proto::Message;
pub use proto::OpCode;
pub use proto::WebsocketStream;
pub use server::Builder as ServerBuilder;
pub use tls::Connector;
pub use tls::MaybeTlsStream;
pub use self::http::upgrade_request;
Modules
client
http-integration
and client
http::Request
objects for HTTP/1.1 Upgrade requests
with websocket servers.server
rustls
and
native-tls
connector and stream types.