TCP (Client) Networking in Pure Bash
Recently I re-remembered about /dev/tcp
- a virtual bash file system that allows you to directly connect to a remote TCP endpoint - without the use of nc
/ netcat
/ ncat
.
While it only allows you to connect (no listening, sadly), it's still a great bash built-in that helps avoid awkward platform-specific issues.
Here's how you'd listen for a connection with netcat
, sending as many random numbers as possible to the poor unsuspecting client:
netcat -l 0.0.0.0 6666 </dev/urandom
Here's how you'd traditionally connect to that via netcat
:
netcat X.Y.Z.W 6666 | pv >/dev/null
The pv
command there is not installed by default, but is a great tool that shows the amount of data flowing through a pipe. It's available in the repositories for most Linux distributions without any special configuration required - so sudo apt install pv
should be enough on Debian-based distributions.
Now, let's look at how we'd do this with pure bash:
pv >/dev/null </dev/tcp/X.Y.Z.W/6666
Very neat! We've been able to eliminate an extra child process. The question is though: how do they compare performance-wise? Well, that depends on how we measure it. In my case, I measured a single connection, downloading data as fast as it can for 60 seconds.
Another test would be to open many connections and download lots of small files. While I haven't done that here, I theorise that the pure-bash method would win out, as it doesn't have to spawn lots of subprocesses.
In my test, I did this:
# Traditional method
timeout 60 nc X.Y.Z.W 6666 | pv >/dev/null
# Pure-Bash method
timeout 60 pv >/dev/null </dev/tcp/X.Y.Z.W/6666
The timeout
command kills the process after a given number of seconds. The server I connected to was just this:
while true; do nc -l 0.0.0.0 6666 </dev/urandom; done
Running the above test, I got the following output:
$ timeout 60 pv >/dev/null </dev/tcp/172.16.230.58/6666
652MiB 0:00:59 [11.2MiB/s] [ <=> ]
$ timeout 60 nc 172.16.230.58 6666 | pv >/dev/null
599MiB 0:01:00 [11.1MiB/s] [ <=> ]
Method | Total Data Transferred |
---|---|
Traditional | 599MiB |
Pure Bash | 652MiB |
As it turns out, the pure bash method is apparently faster - by ~8.8%. I think this might have something to do with the lack of the additional sub-process, or some other optimisation that bash can apply when doing the TCP networking itself.
Found this interesting? Got a cool use for it? Discovered another awesome bash built-in? Comment below!