Go语言实现简单RPC调用_Golang服务通信实战

不能。net/rpc默认用Gob编码、不跨语言、无超时重试和服务发现,仅适合学习或单机通信;生产环境应选gRPC等成熟框架。

Go标准库net/rpc能直接用于生产环境吗

不能。标准库net/rpc默认使用Gob编码,不跨语言,HTTP传输层需手动包装,且无超时控制、重试、服务发现等能力。它适合学习RPC原理或单机模块间轻量通信,但线上微服务应优先选gRPCKitex等成熟框架。

net/rpc服务端注册函数必须满足什么签名

必须是公开方法(首字母大写),接收两个指针参数,返回error

func (t *T) MethodName(argType *ArgType, replyType *ReplyType) error

常见错误包括:

  • argTypereplyType不是指针类型 → 报错"rpc: method has wrong number of ins"
  • 方法非导出(小写开头)→ 注册静默失败,客户端调用时返回"method not found"
  • 第二个参数不是指针 → "rpc: reply type is not a pointer"
  • 返回值不是error或数量不对 → 启动时报"method has wrong number of outs"

http.ServeMux挂载rpc.Server时为什么客户端连不上

rpc.Server默认注册在"/_goRPC_"路径,但ht

tp.ServeMux不会自动转发该路径——必须显式调用rpc.HandleHTTP(),它会注册"/rpc""/debug/rpc"两个handler。

正确做法:

rpc.Register(new(HelloService))
rpc.HandleHTTP()
http.ListenAndServe(":8080", nil)

如果自己用http.ServeMux,需手动绑定:

mux := http.NewServeMux()
rpc.HandleHTTP()
// 此时 rpc.DefaultServer 的 HTTP handler 已注册到 DefaultServeMux
// 若想用自定义 mux,必须用 rpc.Server.ServeHTTP 手动分发
srv := rpc.NewServer()
srv.Register(new(HelloService))
http.Handle("/rpc", srv)

客户端调用Call后一直阻塞,可能原因有哪些

最常见的是网络不通或服务未监听,但还有几个隐蔽点:

  • 服务端Listen用的是localhost,而客户端连127.0.0.1(或反之)→ IPv4/IPv6解析差异导致连接被拒绝
  • 客户端dial未设超时:rpc.DialHTTP("tcp", "127.0.0.1:8080")会无限等待TCP握手完成 → 必须用rpc.DialHTTPPath配合net.DialTimeout封装
  • Call第三个参数传了非指针变量 → 返回值无法写入,但不会报错,只是reply保持零值
  • 服务端函数panic未recover → 连接被断开,客户端收到"connection reset"而非业务错误

建议始终用带超时的拨号:

conn, err := net.DialTimeout("tcp", "127.0.0.1:8080", 3*time.Second)
if err != nil {
    log.Fatal(err)
}
client := rpc.NewClient(conn)

真实 RPC 场景里,序列化格式、连接复用、上下文取消、错误分类这些点,标准库都不管——写完一个能跑的 demo 很快,但让它的行为可预测、可调试、可运维,才是真正花时间的地方。