权限被拒绝主因是socket路径父目录不可写或umask限制;需用os.mkdirall设0755权限、listenunix后调os.chmod改权,或启动前syscall.umask(0);务必清理旧sock文件并设read/writedeadline防阻塞。

监听 net.ListenUnix 时权限被拒绝?检查 socket 路径和 umask
常见错误是启动服务时报 permission denied,尤其在 Linux 上。根本原因不是代码写错,而是 Unix domain socket 文件路径的父目录不可写,或进程 umask 拦截了 socket 文件的可写权限。
-
os.MkdirAll创建 socket 所在目录时,必须显式指定权限(如0755),否则默认可能只有0700,导致其他用户/进程无法连接 - 启动前调用
syscall.Umask(0)(注意:这会全局修改 umask,慎用)或更安全地——用os.Chmod在ListenUnix后立即修正 socket 文件权限 - socket 路径建议用绝对路径,避免相对路径引发工作目录依赖;
/tmp/myapp.sock比./sock更可靠
用 net.UnixListener 处理连接时,为什么客户端连不上就卡住?
Unix domain socket 是字节流(stream)协议,默认行为和 TCP 一致,但没有网络超时机制。如果客户端异常退出、未发送 EOF、或服务端未设读写 deadline,conn.Read 可能永久阻塞。
- 务必对每个
net.Conn调用SetReadDeadline和SetWriteDeadline,哪怕只设几秒(如time.Now().Add(5 * time.Second)) - 不要复用同一个
net.UnixConn多次Read而不检查io.EOF或syscall.ECONNRESET—— 客户端崩溃后服务端不感知,就会挂住 - 若需消息边界,自己加长度头或分隔符;
net.UnixListener不提供“按消息接收”能力,别指望像 UDP 那样自动拆包
syscall.SO_REUSEADDR 在 Unix socket 里有用吗?
没用。这是 TCP/IP 栈的概念,Unix domain socket 不走 IP 协议栈,内核不识别该 socket 选项。试图用 Control 函数设置它会静默失败或 panic(取决于 Go 版本)。
- Unix socket 的“地址重用”靠的是文件系统:只要 socket 文件存在,
ListenUnix就会报address already in use - 正确做法:启动前用
os.Remove清理旧 socket 文件(并忽略os.IsNotExist错误) - 清理后仍报错?可能是上个进程没退出干净,用
lsof -U | grep myapp查残留句柄
性能瓶颈常出在 accept 循环还是 Read/Write?
绝大多数场景下,瓶颈不在 accept,而在后续 I/O 和业务逻辑。Unix socket 本身延迟极低(纳秒级),但 Go runtime 的 goroutine 调度、内存分配、序列化(如 JSON 编解码)才是真瓶颈。
立即学习“go语言免费学习笔记(深入)”;
- 别盲目开 goroutine 处理每个连接 —— 如果业务逻辑是 CPU 密集型(如加密、压缩),并发太多反而降低吞吐
- 用
sync.Pool复用[]byte缓冲区,避免高频小对象 GC;Unix socket 通信量大时这点很关键 - 监控真实指标:用
runtime.ReadMemStats看堆分配速率,用pprof抓 CPU profile,别只盯着连接数和 QPS
Unix domain socket 的“本地高性能”是真实的,但前提是别把文件系统语义当网络语义用,也别忽略 Go 运行时本身的调度和内存特性。最常被跳过的一步:清理旧 socket 文件 + 设置合理 I/O deadline —— 这两个动作不做,服务跑三天后大概率开始丢连接。











