在Golang中开发RPC客户端与服务端可以借助标准库的net/rpc包实现,该包封装了RPC通信的基础逻辑,开发者只需要按照规范定义服务方法和注册服务即可完成开发。

Golang RPC开发的基础要求
使用net/rpc包开发RPC服务时,需要遵循以下几个基础规则,否则服务无法正常注册和调用:
- 服务方法必须是可导出的,也就是方法名首字母大写
- 方法需要有两个参数,两个参数都必须是可导出的类型或者内建类型
- 方法的第二个参数用来接收返回值,必须是指针类型
- 方法需要返回一个error类型的值
RPC服务端开发步骤
定义服务结构体和方法
首先定义服务对应的结构体,结构体本身不需要包含任何字段,只是作为方法载体,然后定义符合规范的服务方法。
package main
import (
"net"
"net/rpc"
)
// 定义服务结构体
type MathService struct{}
// 定义加法请求参数结构体
type AddRequest struct {
A int
B int
}
// 定义加法响应结构体
type AddResponse struct {
Result int
}
// 实现加法方法,符合RPC方法规范
func (m *MathService) Add(req *AddRequest, resp *AddResponse) error {
resp.Result = req.A + req.B
return nil
}
注册服务并启动监听
完成服务方法定义后,需要将服务注册到RPC服务中,然后启动网络监听等待客户端连接。
func main() {
// 注册MathService服务
err := rpc.Register(&MathService{})
if err != nil {
panic("注册服务失败: " + err.Error())
}
// 监听TCP端口
listener, err := net.Listen("tcp", ":1234")
if err != nil {
panic("监听端口失败: " + err.Error())
}
defer listener.Close()
// 启动RPC服务,接受客户端连接
rpc.Accept(listener)
}
RPC客户端开发步骤
客户端需要先与服务端建立连接,然后通过rpc.Client的Call方法调用远程服务。
package main
import (
"fmt"
"net/rpc"
)
// 定义与服务端一致的请求参数结构体
type AddRequest struct {
A int
B int
}
// 定义与服务端一致的响应结构体
type AddResponse struct {
Result int
}
func main() {
// 连接RPC服务端
client, err := rpc.Dial("tcp", "127.0.0.1:1234")
if err != nil {
panic("连接服务端失败: " + err.Error())
}
defer client.Close()
// 构造请求参数
req := &AddRequest{A: 10, B: 20}
resp := &AddResponse{}
// 调用远程Add方法,第一个参数是服务名.方法名
err = client.Call("MathService.Add", req, resp)
if err != nil {
panic("调用服务失败: " + err.Error())
}
fmt.Printf("计算结果: %dn", resp.Result)
}
开发注意事项
- 客户端和服务端的请求、响应结构体字段名称和类型必须完全一致,否则参数解析会出错
- 如果服务部署在其他机器,需要将连接地址中的127.0.0.1替换为对应的服务器IP
- RPC默认使用Gob编码,如果需要跨语言调用,可以自定义编码方式,比如替换为JSON编码
- 生产环境中需要添加超时控制、错误重试等逻辑,提升服务调用的稳定性
常见问题说明
如果调用时出现rpc: can't find method MathService.Add错误,通常是服务没有正确注册,或者方法名拼写错误。如果返回unexpected EOF错误,一般是客户端和服务端的编码方式不匹配,或者网络连接异常。
注意:net/rpc包在Go 1.21版本之后被标记为废弃,官方推荐使用google.golang.org/grpc等第三方RPC框架,但是net/rpc依然可以正常使用,适合简单的内部服务通信场景。