net/rpc服务必须严格按规范构造:注册导出结构体指针,方法名及字段首字母大写,签名须为func(t, args, *reply) error,http模式路径与dial方式须完全匹配,客户端需显式close连接。

net/rpc 不是“设置”出来的,而是按规范构造、注册、启动的。直接用 rpc.Register 或 rpc.HandleHTTP 前不满足结构体、方法、类型导出等硬性条件,服务就起不来,客户端调用必报 rpc: can't find service 或 gob error: type not registered。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
服务端必须注册导出结构体指针,且方法签名严格匹配
net/rpc 只认「首字母大写的结构体 + 指针接收者 + 特定函数签名」这一种组合,其他写法运行时不报错,但调用时直接失败。
- 方法名必须首字母大写(如
Add),否则反射找不到 - 接收者必须是指针类型(
*Arith),不能是值类型或小写类型(如arith) - 方法签名必须是
func(<em>T, </em>Args, *Reply) error,三个参数全是指针 -
Args和Reply结构体所有字段也必须首字母大写(导出)
type Args struct { A, B int }
type Reply struct { Result int }
type Arith int
func (t *Arith) Add(args *Args, reply *Reply) error {
reply.Result = args.A + args.B
return nil
}
// ✅ 正确注册
rpc.Register(new(Arith))
// ❌ 错误:传值、小写类型、或没加 *
// rpc.Register(Arith{})
// rpc.Register(&arith{})
HTTP 模式下路径和 Dial 方式必须严格对应
用 HTTP 暴露 RPC 服务最易踩坑:路径不一致、Dial 函数选错、handler 绑错 server 实例。- 服务端若用
rpc.HandleHTTP(),它默认把 handler 挂到rpc.DefaultServer上,且路径固定为/rpc - 客户端必须用
rpc.DialHTTP("tcp", "@#@#@#@#@#@#@#@#@#@0")—— 注意是完整 URL,不是 host+path 拆开传 - 若用了自定义
rpc.Server(比如server := rpc.NewServer()),就不能再调rpc.HandleHTTP(),得手动挂:server.Register(new(Arith)) http.Handle("/rpc", server.HTTPHandler()) - 浏览器访问
@#@#@#@#@#@#@#@#@#@0返回405 Method Not Allowed是正常现象,RPC 只响应 POST 请求
客户端必须显式 close,且参数/返回值类型要可 gob 编码
rpc.Client 底层持有 TCP 连接或复用 http.Transport,不关就会泄漏文件描述符,压测时很快触发 too many open files。
- 每次
rpc.Dial或rpc.DialHTTP后,务必defer client.Close() - 参数和 reply 类型不能含
map[interface{}]interface{}、未导出字段、闭包、匿名函数等 - 时间类型用
time.Time没问题(gob内置支持),但自定义 time wrapper 必须实现gob.GobEncoder - 所有字段必须导出(首字母大写),哪怕只是临时调试:
type Args struct {
A int `json:"a"` // json tag 不影响 gob,但字段名 A 必须大写
}
真正难的不是写几行代码,而是所有环节——结构体定义、字段导出、方法签名、注册时机、HTTP 路径、Dial URL、连接关闭——全部对齐。漏掉任意一个,错误信息都藏在底层,不会明确告诉你哪错了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










