Hello world!

This guide assumes that you have some knowledge of the Rust programming language and are using Rust 1.39.0 or higher. To use Tokio with earlier versions of Rust, please check out the Tokio 0.1 docs.

To check your version of Rust on the command line:

rustc --version
rustc 1.39.0 (4560ea788 2019-11-04)

In version 1.39.0 Rust introduced async-await, see the Async Book for in-depth documentation of these new Rust language features. This guide also seeks to provide a practical, hands-on introduction for all of the Rust language features that are needed for programming with Tokio.

Also, most readers will have some experience with writing networking code using the Rust standard library or another language, though folks who are new to network programming should also be able to follow along.

Introducing asynchronous programming

As our first introduction to asynchronous programming with Tokio, we will start with a tiny app that sends “hello, world!” over a network connection.

The difference between Tokio and a Rust program written using the standard library is that Tokio has the flexibility to avoid blocking program execution when the stream is created or when our “hello, world!” message is written to the stream.

Tokio’s net module provides the same abstraction over networking as the corresponding modules in std except asynchronously.

Communicating through a network connection

When developing network code, it’s helpful to use tools that let us simulate each end of the connection. We’ve chosen two to allow us to receive text (listen on a socket and read data) and send text (write data).

We’ll start by sending “hello” over a reliable networking connection (TCP). Before writing code in Rust, let’s install and use some network tools to manually do what our code will do later in the guide.

Install socat, which is a network utility that we’ll use to simulate a server. Then type the following command to print out everything that is received on port 6142 (a somewhat arbitrary number we have chosen for this example):

socat TCP-LISTEN:6142,fork stdout

An easy way to simulate a client (for a text-based protocol) is to use telnet. To connect to our simulated server, we’ll open a different window (so we can see two terminals side-by-side) and type the following on the command-line:

telnet localhost 6142

Telnet will output something like this:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

Now if we type hello and press return, we should see hello printed by socat.

To escape from our TCP session (^]), we need to hold down Ctrl key and type ]). Then at the telnet prompt (telnet >), typing quit will close the connection and exit the program.

Let’s quit telnet and write some Rust code to send some text to our server. We’ll leave socat running, so we can connect to it with our new app!

Let’s write some code!

Next we’ll write some code to create a TCP stream and write “hello, world!” to the stream using Tokio.

Let’s get started by generating a new Rust app:

$ cargo new hello-world
$ cd hello-world

For a quick start, we’ll add the Tokio crate with all Tokio of its features to our Cargo manifest, by adding the following text to Cargo.toml.

[dependencies]
tokio = { version = "0.2", features = ["full"] }

Then we’ll replace main.rs with our “hello world” code:

# #![deny(deprecated)]

use tokio::net::TcpStream;
use tokio::prelude::*;

#[tokio::main]
async fn main() {
    let mut stream = TcpStream::connect("127.0.0.1:6142").await.unwrap();
    println!("created stream");

    let result = stream.write(b"hello world\n").await;
    println!("wrote to stream; success={:?}", result.is_ok());
}

The #[tokio::main] macro provides common boilerplate for setting up the tokio runtime, so that we can write main() as an async function. This enables us to call asynchronous functions and write sequential code as if they were blocking by using the Rust await keyword.

Now when we run our app with cargo run (in a different window from where we are running socat), we should see socat print hello world.

下一步

Now that we have successfully built a tiny client to get a feel for network programming with Tokio, we’ll dive into more detail about how everything works.

下一篇Cargo dependencies