Rust Day 7: Tokio — Simple TCP Server

Arjun Sunil Kumar
Rust Go C++
Published in
4 min readApr 26, 2022

Hurray! We have completed 1 week with RUST :)

Today, I plan to cover building a simple tcp_server using tokio.

RUST CODE:

Previously we used use tokio::io::AsyncWriteExt; . This time we are using both use tokio::io::{AsyncReadExt, AsyncWriteExt}; as we are planning to read and write using the socket.

AsyncReadExt is an extension trait (interface) of AsyncRead from futures crate.

https://docs.rs/futures/0.2.1/futures/io/trait.AsyncRead.html
  1. Instead of TcpStream, we are using use tokio::net::TcpListener;
  2. We are also using use std::env; to read command-line arguments.
  3. let addr = env::args()
    .nth(1)
    .unwrap_or_else(|| “127.0.0.1:8080”.to_string());

We use this nth(x) to fetch the 1st (ie nth) argument from the args.

5. let listener = TcpListener::bind(&addr).await?;: Used to bind to the address in the machine.

Going back to my old java HTTP server example,

https://github.com/arjunsk/java-networking/blob/6c6d6fe65eee2f176e7d8fc52d2997e808071d27/server-examples/ck-server/ck-server-core/src/main/java/com/arjunsk/server/ck/CkHttpServer.java

The standard syntax involves

  • binding a port address
  • Run an infinite loop. socket.accept() would wait() the thread or main threaduntil a new connection request is established.
  • When a new incoming connection request comes, socket.accept() would return a socket that will have an input stream and an output stream to communicate (io) with the client. Note that, we would get input stream and output stream as Sockets are bidirectional.
  • The new request can be handled in a new thread, without halting the listening.

6. loop{} is used similar to while(true){}

7. let (mut socket, _) = listener.accept().await?; is used to accept a new inbound connection.

8. tokio::spawn( Task ) is used to start a new thread ie async task.

https://tokio.rs/tokio/tutorial/spawning

Instead of spawning a new task, we can also make it sequential. Here the socket established is passed on to the process function.

Or similar to our original code, we can try

https://durch.github.io/rust-goauth/tokio/fn.spawn.html

9. move : converts any variables captured by reference or mutable reference to variables captured by value. move is often used when threads are involved.

In our case, it is used mainly to pass the ownership of the socket to the inside thread.

Without Move:

We get the output as 3 ie the length of the vector.

With Move:

The error occurs as the value is not existential after the move.

10. vec![0; 1024]; This syntax is used to declare a vector of size 1024 initializing all the values as 0.

From SO:

11. In the new thread that we have now, we will continuously read from the socket and write the same content back to the socket.

let n = socket
.read(&mut buf)
.await
.expect("failed to read data from socket");

n denotes how many bytes were read.

read(&mut buf) read content into the buffer vector.

12. .expect(“error message”)

From SO:

I can “expect” a result to be Ok, I can "expect" an Optional value to be Some. I can also write in test, where I "expect" a web request to be successful. I would write do_request().expect("Expected request to be successful"). This gives me a clear and concise message of what went wrong instead of having to go through the stacktrace when using unwrap.

https://learning-rust.github.io/docs/e4.unwrap_and_expect.html
https://learning-rust.github.io/docs/e4.unwrap_and_expect.html

13. Writing it back:

socket                    
.write_all(&buf[0..n])
.await
.expect("failed to write data to socket");

We are writing the buf value from 0 to n (ie all the read values) and sending it back to the client.

Conclusion:

This was a relatively simpler session. In the next session, I plan to cover tinydb using tokio, which uses Concurrent HashMap.

Found it Interesting?

Please show your support by 👏.

--

--

Arjun Sunil Kumar
Rust Go C++

Writes on Database Kernel, Distributed Systems, Cloud Technology, Data Engineering & SDE Paradigm. github.com/arjunsk