Networked Pipes with Netcat

Netcat, often invoked with the nc command, can be thought of as a little bit like a network version of the cat utility. Its basic purpose is to open TCP/IP connections and pass stuff along them. It can:

  • Listen for a network connection on a given port, and echo anything it receives to stdout.
  • Connect to a given host and port, and send anything it receives on stdin.

...and much more, but these features are all we need to wire up commands in the shell on a desktop computer to a running instance of raspipe.py on a Raspberry Pi elsewhere on the network.

Transmitting and Receiving

Let's start with a simple example of connecting two netcat instances and sending some text between them. Here are two terminals running on my laptop:

In the first terminal, I tell netcat to listen on port 1234 by saying:

Download: file
netcat -l 1234

In the second terminal, I tell netcat to connect to localhost (which is, as you might suspect, a special hostname that should resolve to the machine we're on right now), port 1234:

Download: file
netcat localhost 1234

Now, in either window, I can type some text and hit enter, and it'll show up in the other window. Once I'm done typing, I can hit Ctrl-D, a conventional shortcut for end-of-file, and the connection will close.

You can try this on your Raspberry Pi. If you're running the desktop, just start a couple instances of LXTerm.  If you're on the console, try pressing Alt and the right arrow key until you see a new login prompt. You can use Alt+arrows to navigate back and forth between these virtual consoles.

Wiring Netcat to RasPipe

Now take a look at listener_pitft.sh:

Download: file
nano listener_pitft.sh
Download: file
#!/usr/bin/env bash 
echo "Listening on port 5280" 
netcat -l 5280 -k | ./raspipe_pitft.sh

This script just invokes netcat, listening on port 5280, with -k, which says to listen for a new connection once the current one closes. (Normally, the program will exit as soon as one connection finishes.)

It then pipes the output of this netcat instance to raspipe_pitft.sh.

In order to test this, you'll need an installed PiTFT display and a working network connection on your Pi. You can check your current network address with ifconfig, like so:

Download: file
[email protected] ~/Adafruit-RasPipe $ ifconfig
eth0      Link encap:Ethernet  HWaddr b8:27:eb:73:15:91  
          inet addr:192.168.1.4  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:148486 errors:0 dropped:0 overruns:0 frame:0
          TX packets:18536 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:27686012 (26.4 MiB)  TX bytes:3096689 (2.9 MiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:2821 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2821 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:381840 (372.8 KiB)  TX bytes:381840 (372.8 KiB)

I looked for the inet addr:192.168.1.4 entry in the eth0 section. Yours might be under wlan0, if you're using a wireless adapter instead of an ethernet cable. Once you know your address, start the listener like so:

Download: file
./listener_pitft.sh

Now, from a terminal elsewhere on your network, try sending some traffic to your Pi:

Download: file
echo "hello\nworld\ni\nam\na\pi" | netcat 192.168.1.4 5280

If netcat isn't available, try typing nc instead. You should see something like the following:

You can experiment with other input - just about anything should work.

Netcat on Windows

This all works fine if your desktop/laptop is a Linux or OS X machine, but what about Windows users?

Not to worry: The authors of the Nmap network scanning tool provide Ncat, "much-improved reimplementation of the venerable Netcat", for Windows. To run, just visit the Ncat page and find the zip file containing the standalone executable. I opened this and dragged a copy of ncat to my desktop:

...then just ran cmd.exe, followed by:

Download: file
cd Desktop
ncat 192.168.1.4 5280

An Inline Utility for Piping to RasPipe

Ok, so my original goal for this project was to make a pipeline viewer that would let me drop a command into the middle of other shell one-liners and have output displayed on the Raspberry Pi.

Using a feature of Bash called process substitution, this turns out to be pretty easy.

Download: file
nano raspipe_tee
Download: file
#!/usr/bin/env bash

RASPIPE_ADDY=192.168.1.4
cat /dev/stdin | tee >(netcat $RASPIPE_ADDY 5280)

We use cat /dev/stdin to spit out the contents of standard input for this script, and pipe it to tee, which serves to redirect input to a file while also echoing it back to standard output.

In tee >(netcat $RASPIPE_ADDY 5280), the >(...) section creates a special temporary file of sorts, which tee writes to as if it were any other file. The difference is that when it writes to this file, it's actually writing to the stdin of netcat. Crazy, right?

So now we can say something like:

Download: file
fortune | ./raspipe_tee

...and have the same output echoed on the PiTFT.

What's more, we can issue a command that uses the output of raspipe_tee and still see the output of fortune echoed on the PiTFT.

Download: file
fortune | ./raspipe_tee | wc -w

In order to test this, you can either ssh to your Pi and run raspipe_tee there, or copy it to another machine and replace the value of RASPIPE_ADDY with the address of your Pi.

This guide was first published on Mar 26, 2015. It was last updated on Mar 26, 2015. This page (Networked Pipes with Netcat) was last updated on Jul 22, 2019.