Building a TCP Echo Program in Rust

July 30, 2023

One of the best ways to understand networking is by actually building some network applications. Today, we will be diving into creating a simple TCP Echo program using Rust. In this program, the server will echo whatever the client sends to it.

First, let's make sure that Rust is installed. You can download Rust from the official website: https://www.rust-lang.org/tools/install

After you've installed Rust, create a new project:

$ cargo new tcp_echo
$ cd tcp_echo

Server

Let's start by building the server. In Rust, we use the std::net module for networking tasks. Create a new file named "server.rs" and put the following code in it:

use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;
fn handle_client(mut stream: TcpStream) {
    let mut buf = [0; 512];
    loop {
        match stream.read(&mut buf) {
            Ok(bytes_read) => {
                if bytes_read == 0 { return; } // Client closed connection
                stream.write(&buf[0..bytes_read]).unwrap(); // Echo back to client
            },
            Err(e) => {
                eprintln!("Failed to read from client: {}", e);
                return;
            }
        }
    }
}
fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                thread::spawn(|| {
                    handle_client(stream);
                });
            }
            Err(e) => {
                eprintln!("Failed to accept client: {}", e);
            }
        }
    }
}

In the above code, we first import necessary modules. In the main function, we bind a TCP listener to the localhost IP on port 7878. For each incoming connection, we spawn a new thread to handle the client.

Client

Now let's build the client. Create a new file named "client.rs" and put the following code in it:

use std::io::{stdin, Read, Write};
use std::net::TcpStream;
fn main() {
    let mut stream = TcpStream::connect("127.0.0.1:7878").unwrap();
    loop {
        let mut input = String::new();
        stdin().read_line(&mut input).unwrap();
        stream.write(input.as_bytes()).unwrap();
        let mut buffer = [0; 512];
        stream.read(&mut buffer).unwrap();
        println!("{}", String::from_utf8_lossy(&buffer[..]));
    }
}

In this code, we first establish a connection to the server. Then in a loop, we read the user's input from the standard input, send it to the server, read the server's response, and print it.

To test these programs, open two terminals. In the first one, run:

$ rustc server.rs
$ ./server

And in the second one, run:

$ rustc client.rs
$ ./client

Now, whatever you type in the client terminal will be echoed back from the server.

In summary, Rust provides a robust and efficient way to handle network programming tasks with safety guarantees. This example is very basic and real-world networking applications can be much more complex, but this gives you a starting point for building network applications in Rust. Happy Rusting!

Read also

Implementing a TCP Client and Server in Go: A Ping Pong Example
Golang transfer a file over a TCP socket
Generate CRC32 hash of a file in Golang turorial
Generate SHA1 hash of a file in Golang example
Generate MD5 hash of a file in Golang
Why You Should Learn to Program
Comments
Tags