Socket Options & Go: Multiple Listeners, One Port

Benjamin Cane
6 min readApr 3
Photo of two wall sockets with a cat sticker on them
Photo by Sven Brandsma on Unsplash

The net package in the Go standard library abstracts away many low-level networking details, making it easy for Go developers to create complex applications. However, the standard library can confuse developers who want to explore more advanced networking features like setting socket options on listeners.

Today’s article is going to focus on exploring advanced networking options by enabling two processes to bind the same port.

What are socket options?

A socket option is a value that can be set on a socket (UDP or TCP) to modify the default behavior. Socket options are used throughout the Go standard library to provide the network behaviors that we all expect.

A great example of this is Nagle’s algorithm. By default, with Go, every new connection has Nagle’s algorithm dIsabled; this is disabled because, with every new connection, Go will set the TCP_NODELAY socket option.

Beyond the defaults, however, Go also provides convenient methods to enable socket options that can improve TCP/IP connectivity, like setting SO_KEEPALIVE with the tcp.Conn.SetKeepAlive() method.

Many socket options are available, with each Operating System platform implementing them differently. In this article, we will explore the SO_REUSEADDR and SO_REUSEPORT socket options.

A Basic TCP Listener

First, we must create an example TCP server application to showcase how to modify listener behavior with socket options. The below example is simple and lacks much of the error handling a production-ready application would need.

package main

import (
"log"
"net"
)

func main() {
// Start Listener
l, err := net.Listen("tcp", "0.0.0.0:9000")
if err != nil {
log.Printf("Could not start TCP listener: %s", err)
return
}

// Wait for new connections
for {
// Accept new connections
c, err := l.Accept()
if err != nil {
log.Printf("Listener returned: %s", err)
break
}

// Kickoff a Goroutine to handle the new connection
go func() {
defer c.Close()
log.Printf("New connection created")

// Write a hello world and close the session
_, err := c.Write([]byte("Hello World"))
if err != nil {
log.Printf("Unable to…
Benjamin Cane

Building payments systems at American Express. Author (https://amzn.to/3kuCFpz). Open-source contributor (https://github.com/madflojo).