4 min read

High-Performance Communication Between Go and Python Using Unix Domain Sockets

While building a real-time video system, I needed fast and secure communication between Go and Python services. Unix Domain Sockets turned out to be the simplest and most powerful solution.
High-Performance Communication Between Go and Python Using Unix Domain Sockets

In modern software systems, it is very common to combine multiple programming languages within the same project. Each language excels at different things: Go is excellent for building high-performance backend services, while Python often shines when working with device protocols, rapid prototyping, and mature third-party ecosystems.

However, once you decide to mix languages, a critical question appears:

How should these components communicate with each other?

During a recent real-time video management project I was working on, I faced exactly this challenge. The backend API layer was written in Go, while all camera-side operations—ONVIF communication, user management, RTSP discovery—were handled by a Python worker. Both services were running on the same machine, but they needed to exchange messages frequently and reliably.

Opening TCP ports, managing firewalls, and introducing unnecessary network layers felt like the wrong direction. What I needed was something faster, safer, and simpler.

That’s when Unix Domain Sockets became the obvious choice.

When the first prototype started working, the experience was striking. Go and Python felt like they were no longer communicating over a network at all—they were simply exchanging messages inside the kernel, fast and effortlessly. This article is a deep dive into that experience, the architecture behind it, and why Unix Domain Sockets can be a hidden superpower in local service communication.

What Is a Unix Domain Socket?

A Unix Domain Socket (UDS) is a mechanism that allows inter-process communication (IPC) between processes running on the same operating system instance, without using the network stack.

From a programming perspective, it behaves very similarly to TCP sockets. From a system perspective, however, it is fundamentally different.

A simple analogy:

If TCP communication is like making a phone call across cities, Unix Domain Sockets are like two people talking in the same room.

No routing, no ports, no IP addresses—just direct communication through the kernel.

The Technical Foundation of UDS

A Unix Domain Socket is represented as a special file in the filesystem:

/run/deviceiq/onvif.sock
/tmp/app.sock
/var/run/docker.sock

Important details:

  • This file is not written to disk
  • It exists as a kernel-managed endpoint
  • The filesystem path is only an address
  • Data is transferred through kernel memory buffers

Applications open, read, and write to this file as if it were a socket, but the kernel handles everything internally.

Why Is UDS Faster Than TCP?

Unix Domain Sockets avoid many expensive layers of TCP/IP communication.

1. No Network Stack

TCP data flow:

Application → Kernel → TCP/IP stack → Routing → Firewall → Peer

UDS data flow:

Application A → Kernel → Application B

2. No Handshake

TCP requires a three-way handshake (SYN, SYN-ACK, ACK).
UDS connections can start sending data immediately.

3. No Packet Fragmentation

Data is transferred as a stream inside the kernel, not as network packets.

4. Fewer Context Switches

Less overhead means lower CPU usage and more stable latency.

In practice, UDS is often 40–60% faster than TCP for local communication.

Security Advantages of Unix Domain Sockets

One of the most elegant aspects of UDS is security.

Instead of managing firewalls and port access, you rely on filesystem permissions:

chmod 660 /run/deviceiq/onvif.sock
chown deviceiq:deviceiq /run/deviceiq/onvif.sock

This makes UDS ideal for:

  • Sensitive backend services
  • Financial or government systems
  • Edge and embedded devices
  • Internal service communication

No open ports. No exposed network surface.

Real-World Scenario: Go Backend → Python ONVIF Worker

In my project, the architecture looked like this:

Go Backend → Unix Domain Socket → Python Worker → IP Camera (ONVIF)

Go Backend Responsibilities

  • Accept REST API requests
  • Validate input
  • Build JSON messages
  • Send them through the Unix socket

Python Worker Responsibilities

  • Parse incoming messages
  • Communicate with the camera via ONVIF
  • Return structured results

Everything happens locally, inside the kernel, with minimal latency and maximum control.

Architecture Flow

Implementing a Unix Domain Socket Server in Go

listener, err := net.Listen("unix", "/run/deviceiq/onvif.sock")

Full example:

package main

import (
    "encoding/json"
    "fmt"
    "net"
    "os"
)

type Request struct {
    Action string                 `json:"action"`
    Data   map[string]interface{} `json:"data"`
}

func main() {
    socket := "/run/deviceiq/onvif.sock"
    os.Remove(socket)

    l, err := net.Listen("unix", socket)
    if err != nil {
        panic(err)
    }
    defer l.Close()

    fmt.Println("Listening on", socket)

    for {
        conn, _ := l.Accept()
        go handle(conn)
    }
}

func handle(conn net.Conn) {
    defer conn.Close()

    var req Request
    json.NewDecoder(conn).Decode(&req)

    resp := map[string]interface{}{
        "status": "ok",
        "echo":   req,
    }

    json.NewEncoder(conn).Encode(resp)
}

Python Worker Using Unix Domain Socket

import socket
import json

SOCKET = "/run/deviceiq/onvif.sock"

client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client.connect(SOCKET)

payload = json.dumps({
    "action": "create_user",
    "data": {"username": "demo"}
})

client.sendall(payload.encode())
response = client.recv(4096)

print("Response:", response.decode())

Unix Domain Socket vs TCP: A Practical Benchmark Perspective

When deciding between Unix Domain Sockets and TCP for inter-process communication, performance is often the key factor. While exact numbers depend on workload and hardware, real-world benchmarks consistently show a clear pattern.

Typical Observations

MetricTCP (localhost)Unix Domain Socket
LatencyHigherLower
ThroughputGoodVery high
CPU usageHigherLower
Context switchesMoreFewer
JitterNoticeableVery stable

In local IPC scenarios, Unix Domain Sockets are commonly 40–60% faster than TCP on the same machine.

Where Unix Domain Sockets Should Be Used

Use UDS When:

  • Services run on the same machine
  • Performance and low latency matter
  • You want secure, port-free communication
  • You are building monolith + worker architectures
  • You are working with system-level services

Common real-world examples:

  • Docker daemon
  • containerd
  • systemd
  • internal backend workers

Where Unix Domain Sockets Should NOT Be Used

Avoid UDS When:

  • Services run on different machines or VMs
  • You need horizontal scaling across nodes
  • You expose public APIs
  • You require network-level routing or firewall rules
  • Cross-platform (Windows/Linux) support is mandatory

UDS is local by design, not distributed.

The Power of Simplicity

What impressed me most about this architecture was how a complex problem—multi-language, high-frequency communication—was solved with an extremely simple tool.

No message brokers.
No HTTP overhead.
No open ports.

Just:

  • One socket file
  • Two processes
  • JSON messages
  • Kernel-level speed

Sometimes, the best engineering solutions are the simplest ones.

Conclusion

Unix Domain Sockets are one of the most effective tools for local inter-process communication:

  • Fast
  • Secure
  • Simple
  • Proven in production

If you are building systems where Go, Python, or other languages need to cooperate on the same machine—especially in camera systems, video processing, AI inference, or system tooling—Unix Domain Sockets are absolutely worth considering.

They might quietly become one of your favorite architectural decisions.