How To Build a CLI Tool To Show Ports Available | Rust

Sometimes, when I'm writing a web application or installing one, I find that is not possible to start it up because the port that is supposed to use is used by other applications.

So, that is the reason I want to create a program that shows me if a port I want to use is available.

This CLI tool is going to have the following features:

  • Show if a specific port is available

  • Read multiple port numbers from the console and return which ones are available.

Requirements

  • Rust installed

For this project, we are going to use the Clap crate for parsing the command line arguments.

cargo.toml

[dependencies]

clap = { version = "4.4.6", features = ["derive"] }

main.rs

First, we are going to create a program that checks a specific port and returns if the port is available or not.


use std::net::TcpListener;

fn main() {
    let port = 3000;

    let is_available = port_is_available(port);

    if  is_available {
        println!("Port: {} is available", port);
    } else {
        println!("Port: {} is NOT available", port)
    }
}

fn port_is_available(port: u16) -> bool {
    match TcpListener::bind(("127.0.0.1", port)) {
        Ok(_) => true,
        Err(_) => false,
    }
}

In the code above, we create the port_is_available function that has port as a parameter and creates a TCP listener to the address passed using the TcpListener::bind() function. The port_is_available function returns true if the TCP listener is ready for connection, and false, otherwise.

In the main function, we declare a variable to store the port we want to check.

Then, we create the is_available variable to store the return value when we call the port_is_available function.

We create a control flow, to print if a port is available or not.

Next, we run the cargo run command in our console.

The image above shows in the console the output of the program when trying to connect to a port that has been used.

Now, instead of having to declare a variable with the port number and run the program, let's add Clap to pass the port number as an argument using the console.

use clap::Parser;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {

    #[arg(short, long)]
    Port: u16,
}

fn main() {
    let args = Args::parse();
    let port = args.Port;
...

}

We compile the program and go to the executable file, I have it this path: target/debug/port-searcher.

Run the following command in our console:

port-searcher --port 8000

So far, we have implemented the first feature of our CLI tool.

Now, let’s add the feature that allows the program to show multiple ports available.

use std::net::TcpListener;

...


fn main() {
   ...    
    let list_of_ports = [3000, 4000, 8000, 8080, 9000, 5000, 9090];
    ports_available(list_of_ports.to_vec());
...
}

fn ports_available(ports: Vec<u16>) {
    for port in ports {
        if port_is_available(port) {
            println!("port {} is available", port);
        } else {
            println!("Port: {} is NOT available", port)
        }
    }
}
...

In the code above, we create a vector with multiple ports. Then, the program iterates through the vector and creates a connection with every port in the list. Showing which one is available.

Now, let's modify the Args struct so our CLI tool can read multiple port numbers from our console.

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {

    #[arg(num_args(0..), short, long)]
    ports: Vec<u16>,

}

fn main() {
    let args = Args::parse();
    let ports = args.ports;

    ports_available(ports.to_vec())

}

We changed the attribute port for ports and the type is a vector of u16 integers.

We run the following command in our console:

port-searcher --ports 4000 3000 5000 9000 8080 9090 5174

Conclusion

In this article, we learn how to check if a port is available, how to use Clap to pass arguments from the command line, and how to check multiple ports.

This is useful when we have multiple services running and we don't know if a port is been used by one of them.

The source code is here.

Thank you for taking the time to read this article.

If you have any recommendations about other packages, architectures, how to improve my code, my English, or anything; please leave a comment or contact me through Twitter, or LinkedIn.

Resources

How to find an available TCP port in Rust

A fast port scanner in 100 lines of Rust

Clap Documentation

1
Subscribe to my newsletter

Read articles from Carlos Armando Marcano Vargas directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Carlos Armando Marcano Vargas
Carlos Armando Marcano Vargas

I am a backend developer from Venezuela. I enjoy writing tutorials for open source projects I using and find interesting. Mostly I write tutorials about Python, Go, and Rust.