unix domain socket是本地跨进程通信的首选方案,因性能远超loopback tcp、支持文件权限控制且全双工可靠;os.pipe()仅限父子进程,独立进程间无效,误用导致broken pipe或eof。

Unix Domain Socket 是唯一能同时满足“跨进程”“高隔离”“高效传递”的方案,其他方式要么不跨进程(os.Pipe()),要么隔离弱(共享内存)、要么性能差(loopback TCP)。
为什么 os.Pipe() 不能用在模块间跨进程通信
很多人把 os.Pipe() 当成通用管道来用,结果一跑独立进程就卡死或报 broken pipe。它返回的是一对 *os.File,本质是内核匿名管道 fd,只在 fork 后父子进程间有效——两个 go run main.go 启动的程序根本看不到对方的 fd。
常见错误现象:
-
read | write: broken pipe或立刻 EOF - goroutine 卡在
Read()或Write()不返回 - 误以为是代码逻辑问题,实际是通信机制选错了
net.Listen("unix", path) 必须做对的三件事
UDS 性能比 loopback TCP 高 2 倍以上,且天然支持文件权限控制,但路径、权限、清理任意一个出错都会导致连接失败。
服务端启动前必须:
- 用
os.RemoveAll(socketPath)清理旧 socket 文件(os.Remove()对残留目录会失败) - 确保
socketPath是绝对路径,例如/tmp/myapp.sock - 其父目录(如
/tmp)有可执行(x)权限,否则客户端连不上(Linux/Unix 路径遍历需要 x)
监听后别写 defer listener.Close() 在 accept 循环外;正确做法是:defer func() { _ = listener.Close() }(),或把 Close() 放进 shutdown 流程里。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
客户端连接失败时不能 panic,得重试
服务端从 Listen 到进入 Accept 循环有微小延迟,客户端如果立即连接,大概率遇到 connect: connection refused。
建议重试策略:
- 最多 3 次重试
- 每次间隔
100 * time.Millisecond - 用
context.WithTimeout控制总耗时,避免无限等待
别用 SOCK_DGRAM:Go 的 net.ListenUnixgram 虽然存在,但只适合发短小、允许丢失的打点消息;模块间通信必须可靠有序,一律用默认的 SOCK_STREAM。
跨语言模块也推荐 UDS,不是“够用”,而是“更稳”
如果你的模块一部分是 Go,一部分是 C++ 或 Python,UDS 仍是首选——它不依赖语言运行时,只依赖 POSIX socket 接口,Windows 10+ 也支持 SOCK_STREAM 模式。
相比 FIFO(mkfifo):
- FIFO 是单向阻塞的,读端
open()会等写端,写端open()会等读端;UDS 连接建立后即全双工 - FIFO 不支持 seek、不支持双向复用;UDS 可以像 TCP 一样
Read/Write任意次 - FIFO 权限控制粒度粗(只有读写位),UDS 可用
chmod精确控制 socket 文件权限
真正容易被忽略的是:服务端 shutdown 时,要主动关闭 listener 并清理 socket 文件;否则下次启动会因 address already in use 失败——这个动作不会自动发生。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










