1. Overview

In this tutorial, we’ll learn how to receive information over a network port and print it to the terminal. First, we’ll use the nc command, also called netcat. Then, we’ll use a similar program called ncat developed by nmap. Finally, we’ll also learn we can use a special file in Bash to connect to a port.

2. Use Case

Sending and receiving information over a network port is useful when communicating between different computers. Sometimes, the communication is within the same computer using the local IP 127.0.0.1. When we use TCP to communicate over the network, the connection has a state. First, there has to be a process bound to a port and in a listening state. Then, another process attempts to connect to the port that the other process is listening to. Finally, once the connection is established, the processes can communicate with each other, and both sides of the connection can send and receive information. Therefore, when we want to receive and print the information that we receive on a port, we have to know if we need to listen or connect to that port. For instance, a program can write logs over the network instead of to a file. In this case, the process may connect to a port and write the logs through it. Alternatively, a process can listen to a port and write the logs to any other process that connects to that port. In the following sections, we’ll suppose there is a program on the same computer that runs continuously and logs the memory usage to port 9100. 

3. Listening on a Port

If we want to listen on a port, we can use nc and configure it to listen on that port using the -l parameter. Then, we have to specify which port we want to bind to using the -p parameter followed by the port number. When we execute nc, it will run in the foreground, waiting for connections. When another process connects, nc will continue running and will print to the terminal everything it receives. Let’s run nc to listen on port 9100:

$ nc -l -p 9100
Sun Jan 14 14:34:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3642760     2523640       26792    10144996    12302388
Swap:       16777212        3096    16774116

Sun Jan 14 14:35:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3643252     2523140       26792    10145004    12301896
Swap:       16777212        3096    16774116

As we can see, nc listened on port 9100, and the other process connected and sent memory usage information. The nc command will terminate if the connected process ends, or if we press Ctrl+C. As nc prints the information to the standard output, we can pipe its output to another command. We can use tee as a t-splitter, so we can see the information and write it to a file at the same time. Let’s use tee to view the information, and write it to the memory_usage_logs.txt file:

$ nc -l -p 9100 | tee memory_usage_logs.txt
Sun Jan 14 14:42:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3870020     2291796       30904    10149580    12071016
Swap:       16777212        3096    16774116
^C
$ cat memory_usage_logs.txt
Sun Jan 14 14:42:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3870020     2291796       30904    10149580    12071016
Swap:       16777212        3096    16774116

Finally, we can use ncat instead of nc, and with the same parameters. ncat has additional functionality to support multiple connections using the -k parameter. This feature prevents ncat from exiting when the other process closes the connection. Instead, ncat keeps listening for new connections. Let’s run ncat to listen on port 9100, adding the -k parameter:

$ ncat -k -l -p 9100
Sun Jan 14 14:50:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     4097840     2067580       26700    10145976    11847400
Swap:       16777212        3096    16774116

In this case, if the other process disconnects and then re-connects, ncat will keep running and accept the new connection.

4. Connecting to a Port

Instead of listening on a port, we may want to connect to a port to receive the information. In this case, the other process listens on a port and sends the information to the process that connects to it. There are two ways to connect to a port. One involves using nc or ncat, and the other involves using a special file.

4.1. Using nc or ncat

When we want to connect to a port, we have to specify the IP and the port number that we want to connect. Sometimes, instead of the IP, we can use a domain name. Once we have the IP and port, we can connect to it using nc. We have to use the IP and the port as the parameters, in that order. Let’s see how to connect to port 9100 on IP 127.0.0.1 using nc:

$ nc 127.0.0.1 9100
Sun Jan 14 16:18:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3260132     2883652       35496    10167612    12676312
Swap:       16777212        3096    16774116

Sun Jan 14 16:19:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3270692     2873076       35492    10167628    12665756
Swap:       16777212        3096    16774116

As we can see, nc is connected to IP 127.0.0.1 port number 9100. Then, it received the information and printed it to the terminal. If we want to use the ncat command, we can use the same parameters:

$ ncat 127.0.0.1 9100
Sun Jan 14 16:27:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3332328     2812052       34188    10167016    12605424
Swap:       16777212        3096    16774116

We can notice, here, that both nc and ncat behave the same way.

4.2. Using a Special File

Finally, there’s another option when we want to connect to a port. We can use Bash functionality that involves opening a special file on /dev/tcp/. This file won’t exist — however, Bash interprets this file as a TCP connection. We can specify the IP as a folder inside /dev/tcp/ and the port as the file. For instance, we can use /dev/tcp/127.0.0.1/9100 to connect to IP 127.0.0.1 port 9100. As that path is treated as a file, we can use cat on that file. However, we have to use Bash redirections to use this functionality. *Let’s try using cat and redirecting /dev/tcp/127.0.0.1/9100 to cat‘s input*:

$ cat </dev/tcp/127.0.0.1/9100
Sun Jan 14 18:01:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3563388     2561448       36236    10186560    12372308
Swap:       16777212        3096    16774116

We can use any program that reads from the standard input. For instance, we can use tee instead of cat. *Let’s redirect the special file to tee‘s standard input, and save the information to a file*:

$ tee memory_usage_logs.txt </dev/tcp/127.0.0.1/9100
Sun Jan 14 18:29:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3654996     2468124       34004    10188276    12282940
Swap:       16777212        3096    16774116
^C
$ cat memory_usage_logs.txt
Sun Jan 14 18:29:00 -03 2022
               total        used        free      shared  buff/cache   available
Mem:        16311396     3654996     2468124       34004    10188276    12282940
Swap:       16777212        3096    16774116

Using this special file is a simple method, and we only need Bash in order to use it. However, this method only works when we need to connect to the port — it’s not available when we need to listen to a port.

5. Conclusion

In this article, we learned how to receive information over the network. First, we saw we can bind to a port and listen to it, using nc or ncat, and print the information to the terminal. Then, we saw we can also receive information by connecting to a port using nc, ncat, or a special file*.*