Accepting sockets
The first thing our Redis server needs to do is to accept inbound TCP sockets. This is done with tokio::net::TcpListener
.
Many of Tokio’s types are named the same as their synchronous equivalent in the Rust standard library. When it makes sense, Tokio exposes the same APIs as
std
but usingasync fn
.
A TcpListener
is bound to port 6379, then sockets are accepted in a loop. Each socket is processed then closed. For now, we will read the command, print it to stdout and respond with an error.
use tokio::net::{TcpListener, TcpStream};
use mini_redis::{Connection, Frame};
#[tokio::main]
async fn main() {
// Bind the listener to the address
let listener = TcpListener::bind("127.0.0.1:6379").await.unwrap();
loop {
// The second item contains the IP and port of the new connection.
let (socket, _) = listener.accept().await.unwrap();
process(socket).await;
}
}
async fn process(socket: TcpStream) {
// The `Connection` lets us read/write redis **frames** instead of
// byte streams. The `Connection` type is defined by mini-redis.
let mut connection = Connection::new(socket);
if let Some(frame) = connection.read_frame().await.unwrap() {
println!("GOT: {:?}", frame);
// Respond with an error
let response = Frame::Error("unimplemented".to_string());
connection.write_frame(&response).await.unwrap();
}
}
Now, run this accept loop:
$ cargo run
In a separate terminal window, run the hello-redis
example (the SET
/GET
command from the previous section):
$ cargo run --example hello-redis
The output should be:
Error: "unimplemented"
In the server terminal, the output is:
GOT: Array([Bulk(b"set"), Bulk(b"hello"), Bulk(b"world")])