Hey! I'm available for hire (and I appreciate tips)  



Ways to test for an available port

It's a Unix System! I know this!

In case you don't know, you can test whether or not a port is in use on your system with namp.

nmap -p 36367 localhost

There's a less elegant way to do it with netstat.

netstat --all --numeric --tcp | grep ':22'

You could also test the failure case with netcat, but you can't easily test the success case because it would start listening on that port.

sudo netcat -l 22
# netcat: Address already in use
netcat -l 22
# (just listens and waits, hit ctrl+c to stop)

A programmatic solution

For this solution I didn't want to install 50MiB of nmap. I wanted something I could test programatically. I decided to do it in go.

Doing it in Go

Here's the heart of it:

  port := "36367"

  ln, err := net.Listen("tcp", ":" + port)

  if err != nil {
    fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s", port, err)
    os.Exit(1)
  }

  _ := ln.Close()
  fmt.Printf("TCP Port %q is available", port)
  os.Exit(0)

And the full thing in context:

package main

import "net"
import "fmt"
import "flag"
import "os"
import "strconv"

func usage() {
    fmt.Fprintf(os.Stderr, "usage: test-local-port [port number]\n")
    flag.PrintDefaults()
    os.Exit(2)
}

func main() {
  flag.Usage = usage
  flag.Parse()

  args := flag.Args()
  if len(args) < 1 {
      fmt.Fprintf(os.Stderr, "Input port is missing.")
      os.Exit(1)
  }

  port := args[0]
  _, err := strconv.ParseUint(port, 10, 16)
  if err != nil {
    fmt.Fprintf(os.Stderr, "Invalid port %q: %s", port, err)
    os.Exit(1)
  }

  ln, err := net.Listen("tcp", ":" + port)

  if err != nil {
    fmt.Fprintf(os.Stderr, "Can't listen on port %q: %s", port, err)
    os.Exit(1)
  }

  err = ln.Close()
  if err != nil {
    fmt.Fprintf(os.Stderr, "Couldn't stop listening on port %q: %s", port, err)
    os.Exit(1)
  }

  fmt.Printf("TCP Port %q is available", port)
  os.Exit(0)
}

Doing it in Node

For reference, here's the same task written with node / io.js.

'use strict';

var net = require('net');
var server = net.createServer();
var port = process.argv[2];

if (!(port && port < 65536)) {
  console.error("Invalid port '%s'", port);
  process.exit(1);
}

server.on('error', function (e) {
  console.error("TCP port '%s' is taken: '%s'", port, e);
  process.exit(1);
});

// Note old versions of node must use the old syntax
// server.listen(port, function () { ... });
server.listen({ port: port, exclusive: true }, function () {
  server.close(function () {
    console.log("TCP port '%s' is available", port);
    process.exit(0);
  });
});

Note that if you're using an old version of node (most versions of node) rather than io.js, you may have to resort to the old listen syntax.

Tradeoffs

One of the targets for what I'm doing with this is Raspberry Pi. The VM initialization time of node.js is significant (seconds). The filesize for the go version is significant (megabytes).

This is also something that I could have reasonably done in C, but hey, who wants to do that? Not me.


By AJ ONeal

Was this useful to you? Share it!

Also, you can give me a tip or hire me.


Published

2015-6-20

Categories


Tags