Unix domain socket 与 TCP/IP 是两种独立机制,服务端需显式监听本地路径(如 /tmp/myapp.sock),客户端用相同路径连接;支持与否取决于启动参数而非配置文件,且路径权限、存在性及命名空间隔离(如 Docker/systemd)是连接成败关键。
Socket 连接不是“配置 TCP/IP 的替代选项”
unix domain socket(
)和 tcp/ip(
)是两类完全不同的底层通信机制,不存在“把 tcp 改成 socket”的配置操作。所谓“用 socket 连接服务器”,本质是服务端必须显式监听一个本地文件路径(如
),客户端也必须用该路径发起连接——它不走网络协议栈,也不依赖 ip 或端口。
服务端是否支持 Unix socket,取决于启动方式而非配置文件
常见服务(如 PostgreSQL、Redis、Nginx、Gunicorn)对 Unix socket 的支持是硬编码在启动逻辑里的,不是靠改个
就能开启。你得确认它启动时用了
、
、
路径含
等明确标识。
PostgreSQL:需在
中设置
,且
可为
(空字符串)或不含
Redis:启动时加
,或配置
Gunicorn:用
,不能混用
和 socket 同一进程
如果你用的是自己写的 Python/Go 服务,必须调用
并
到文件路径,而不是
客户端连接时路径权限和存在性比“怎么写代码”更关键
90% 的“连接失败”不是代码写错,而是:
文件不存在、权限不对(比如服务以 root 启动,客户端普通用户访问被拒)、路径父目录不可执行(
才能进入)、或服务根本没监听这个路径。
检查是否存在:
检查可访问性:
(看 uid/gid 和 mode)
Python 客户端示例(不用 requests,用原生 socket):
curl 不支持 Unix socket;
也不行;要用
或专用工具如
别在 Docker 或 systemd 场景下默认假设 socket 能自动透传
Docker 容器间、或 systemd 服务之间共享 Unix socket,需要显式挂载或配置,不是“同主机就能通”。容器默认无法访问宿主机的
,除非用
;systemd 服务若设了
(默认值),它的
是隔离的,根本看不到其他服务建的 socket 文件。
Docker:宿主机 socket 路径必须通过
映射,且注意 SELinux/AppArmor 可能拦截
systemd:查
;若为
,要么关掉,要么把 socket 放到
下并配
路径建议优先用
(tmpfs,自动清理),而非
(可能被清理或权限混乱)
路径、权限、启动参数这三样对不上,代码再对也没用。尤其在容器或 systemd 环境里,socket 文件看起来“应该存在”,其实根本不在同一个命名空间里。
af_unixaf_inet/tmp/myapp.sockconfig.yml--unix-socketunix_socket_directoriesbind.sockpostgresql.confunix_socket_directories = '/tmp'listen_addresses''localhost-s /tmp/redis.sockunixsocket /tmp/redis.sock--bind unix:/tmp/gunicorn.sock--bind 127.0.0.1:8000socket.socket(socket.AF_UNIX, ...)bind()AF_INET/tmp/myapp.sockchmod 755 /tmpls -l /tmp/myapp.sockstat /tmp && stat /tmp/myapp.sockimport socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect('/tmp/myapp.sock')
s.send(b'PING')
print(s.recv(1024))wgetnc -U /tmp/myapp.socksocat/tmp/*.sock-v /tmp:/tmpPrivateTmp=yes/tmp-vsystemctl show myservice | grep PrivateTmpyes/runRuntimeDirectory=/run/myapp.sock/tmp