Of course! Here's a comprehensive guide to using Unix domain sockets (UDS) in Python, covering both the server and client sides, with detailed explanations and examples.

What are Unix Domain Sockets?
Unix Domain Sockets (UDS) are a method of inter-process communication (IPC) used by programs running on the same host machine.
Key Characteristics:
- IPC Only: They cannot be used for network communication between different machines.
- File-Based: Communication happens through a special file, called a "socket file," located in the filesystem (e.g.,
/tmp/my_socket.sock). This file acts as an endpoint for communication. - High Performance: UDS are generally faster than TCP/IP sockets for local communication because they bypass the network stack (no need for IP/TCp headers, routing, etc.).
- Simple API: The Python API for UDS is very similar to the one for TCP/IP sockets (
socket.socket), making it easy to learn if you already know network programming.
Core Concepts
- Server: A program that listens for incoming connections on a specific socket file.
- Client: A program that connects to the server's socket file to send and receive data.
- Socket File: The "address" of the server. It's a regular file on disk, but the OS treats it specially. Important: If a server crashes or is killed, the socket file might not be deleted. You may need to manually remove it (
rm /tmp/my_socket.sock) before the server can start again. - Connection-Oriented: Like TCP, UDS uses a connection-based model (
socket.SOCK_STREAM). The client connects, and a stable, two-way communication channel is established.
Example 1: A Simple Echo Server and Client
This is the "Hello, World!" of socket programming. The server receives a message from the client and sends it back.
The Server (server.py)
The server's job is to:

- Create a socket.
- Bind it to a specific file path.
- Listen for incoming connections.
- Accept a connection.
- Receive data, process it (echo it), and send it back.
- Clean up.
# server.py
import socket
import os
# Define the socket file path
SOCKET_FILE = "/tmp/my_socket.sock"
# Remove the socket file if it already exists
try:
os.unlink(SOCKET_FILE)
except OSError as e:
if os.path.exists(SOCKET_FILE):
raise e
# Create a Unix domain socket
# AF_UNIX for Unix domain sockets
# SOCK_STREAM for a reliable, connection-oriented stream
server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
# Bind the socket to a file
server_socket.bind(SOCKET_FILE)
# Listen for incoming connections (backlog of 1)
server_socket.listen(1)
print(f"Server listening on {SOCKET_FILE}...")
# Accept a connection
connection, client_address = server_socket.accept()
print(f"Connection from {client_address}")
try:
# Receive data from the client (up to 1024 bytes)
data = connection.recv(1024)
print(f"Received: {data.decode('utf-8')}")
# Echo the data back to the client
connection.sendall(data)
print("Data echoed back to client.")
finally:
# Clean up the connection
connection.close()
print("Connection closed.")
# Clean up the socket file
os.unlink(SOCKET_FILE)
print("Server shut down.")
The Client (client.py)
The client's job is to:
- Create a socket.
- Connect to the server's socket file.
- Send data.
- Receive the echoed data.
- Clean up.
# client.py
import socket
# Define the socket file path (must match the server)
SOCKET_FILE = "/tmp/my_socket.sock"
# Create a Unix domain socket
client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
# Connect to the server
print(f"Connecting to {SOCKET_FILE}...")
try:
client_socket.connect(SOCKET_FILE)
except socket.error as e:
print(f"Could not connect to the server: {e}")
exit(1)
try:
# Message to send
message = b"Hello from client!"
print(f"Sending: {message.decode('utf-8')}")
# Send the message to the server
client_socket.sendall(message)
# Receive the echoed data from the server
data = client_socket.recv(1024)
print(f"Received from server: {data.decode('utf-8')}")
finally:
# Clean up the connection
client_socket.close()
print("Connection closed.")
How to Run It
-
Start the server:
python3 server.py
The server will print:
Server listening on /tmp/my_socket.sock...and wait. -
In a new terminal, start the client:
(图片来源网络,侵删)python3 client.py
Expected Output:
Server Terminal:
Server listening on /tmp/my_socket.sock...
Connection from /tmp/my_socket.sock
Received: Hello from client!
Data echoed back to client.
Connection closed.
Server shut down.
Client Terminal:
Connecting to /tmp/my_socket.sock...
Sending: Hello from client!
Received from server: Hello from client!
Connection closed.
Example 2: Handling Multiple Clients (with Threads)
A real-world server needs to handle multiple clients concurrently. We can use Python's threading module for this.
The Multi-Threaded Server (server_threaded.py)
This server will handle each client connection in a separate thread.
# server_threaded.py
import socket
import os
import threading
SOCKET_FILE = "/tmp/threaded_socket.sock"
def handle_client(connection, client_address):
"""Function to handle a single client connection."""
print(f"[NEW CONNECTION] {client_address} connected.")
try:
while True:
# Receive data from the client
data = connection.recv(1024)
if not data:
# If recv returns an empty object, the client has closed the connection
break
print(f"[{client_address}] Received: {data.decode('utf-8')}")
# Echo the data back
connection.sendall(data)
print(f"[{client_address}] Data echoed back.")
except ConnectionResetError:
print(f"[{client_address}] Client forcibly closed the connection.")
finally:
connection.close()
print(f"[{client_address}] Connection closed.")
def main():
# Clean up old socket file
try:
os.unlink(SOCKET_FILE)
except OSError:
if os.path.exists(SOCKET_FILE):
raise
server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server_socket.bind(SOCKET_FILE)
server_socket.listen(5) # Increased backlog
print(f"Server listening on {SOCKET_FILE}...")
try:
while True:
# Accept a new connection
conn, addr = server_socket.accept()
# Create a new thread to handle the client
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
print(f"[ACTIVE CONNECTIONS] {threading.active_count() - 1}")
except KeyboardInterrupt:
print("\nServer is shutting down...")
finally:
server_socket.close()
os.unlink(SOCKET_FILE)
print("Server shut down.")
if __name__ == "__main__":
main()
The Client (can reuse the first client.py)
You can use the same client.py from the first example.
How to Run It
-
Start the threaded server:
python3 server_threaded.py
-
Open two or more new terminals and run the client in each:
# Terminal 1 python3 client.py # Terminal 2 python3 client.py # Terminal 3 python3 client.py
Expected Output (Server Terminal):
Server listening on /tmp/threaded_socket.sock...
[NEW CONNECTION] /tmp/threaded_socket.sock connected.
[/tmp/threaded_socket.sock] Received: Hello from client!
[/tmp/threaded_socket.sock] Data echoed back.
[ACTIVE CONNECTIONS] 1
[NEW CONNECTION] /tmp/threaded_socket.sock connected.
[/tmp/threaded_socket.sock] Received: Hello from client!
[/tmp/threaded_socket.sock] Data echoed back.
[ACTIVE CONNECTIONS] 2
[NEW CONNECTION] /tmp/threaded_socket.sock connected.
[/tmp/threaded_socket.sock] Received: Hello from client!
[/tmp/threaded_socket.sock] Data echoed back.
[ACTIVE CONNECTIONS] 3
You'll see the server handling each client in its own thread without blocking the others.
Key Differences from TCP/IP Sockets
| Feature | Unix Domain Socket (UDS) | TCP/IP Socket |
|---|---|---|
| Address Family | socket.AF_UNIX |
socket.AF_INET (IPv4) or socket.AF_INET6 (IPv6) |
| Address Format | A string representing a file path (e.g., "/tmp/my.sock") |
A tuple (e.g., ("127.0.0.1", 8080)) |
| Communication Scope | Same host machine only | Any machine on the network |
| Performance | Faster (no network stack overhead) | Slower (due to network stack) |
| Security | Filesystem permissions (read/write/execute) apply to the socket file. | Network-level firewalls and port security. |
| Error Handling | FileNotFoundError if the socket file doesn't exist. |
ConnectionRefusedError if no one is listening on the port. |
When to use UDS:
- Communication between services on the same machine (e.g., a web server and a cache service).
- When performance is critical and the communication is local.
- When you want to leverage filesystem permissions for access control.
When to use TCP/IP:
- Communication between different machines.
- When you need to communicate over the internet.
- When you are building a general-purpose network service.
