Go RPC 服务方法签名的要求

在 Go 中,RPC 方法的签名有严格的要求,主要是为了保证方法的调用能够通过网络正确地传输和解析。具体要求如下:

1. 方法必须是导出的

RPC 服务的方法必须是导出的(即首字母大写)。这是因为 Go 的反射机制要求服务方法可以被外部访问。

复制代码
// 错误示例:方法首字母小写,无法被外部访问
func (s *Server) add(req Req, res *Res) error {
    res.Num = req.NumOne + req.NumTwo
    return nil
}

// 正确示例:方法首字母大写,允许外部调用
func (s *Server) Add(req Req, res *Res) error {
    res.Num = req.NumOne + req.NumTwo
    return nil
}

2. 方法签名要求

RPC 方法必须满足以下签名要求:

  • 方法的参数必须是导出的类型(即结构体类型的字段必须是导出的)。Go 的反射机制依赖这些字段。

  • 方法的第一个参数是请求参数,必须是值类型或指针类型。通常使用指针类型,因为这样可以在方法内部修改传入的参数。

  • 方法的第二个参数是响应参数,必须是指针类型。RPC 调用会修改该参数的值,将结果返回给客户端。

  • 方法的返回值只能是一个 error 类型 ,RPC 系统通过返回的 error 类型来判断调用是否成功。如果返回 nil,表示调用成功;否则,返回错误信息。

    // 正确示例
    func (s *Server) Add(req *Req, res *Res) error {
    res.Num = req.NumOne + req.NumTwo
    return nil // 这里返回nil表示方法执行成功
    }

    // 错误示例:返回两个参数(不符合签名要求)
    func (s *Server) Add(req *Req, res *Res) (int, error) {
    res.Num = req.NumOne + req.NumTwo
    return res.Num, nil // 返回值不符合要求
    }

3. 参数和返回值

  • 请求参数(req:RPC 方法的第一个参数通常是客户端发送的数据,它必须是一个结构体(或者其他类型),并且是值类型或指针类型。常见做法是使用结构体作为请求参数,且通常使用指针类型来提高效率。

  • 响应参数(res:第二个参数是用于返回结果的,它必须是一个指针类型,RPC 会通过这个指针修改返回的结果。

  • 错误返回值 :RPC 方法返回的错误值是必须的。RPC 系统通过检查 error 来判断请求是否成功。如果方法执行成功,error 应该返回 nil;否则,返回错误信息。

4. 方法必须是同步的

RPC 方法是同步调用的,客户端会阻塞直到服务器完成请求并返回结果。RPC 系统会自动管理并发问题,但每个方法调用必须是同步的。如果需要异步行为,通常需要在方法内部使用 goroutine 来处理。

示例:符合要求的 RPC 方法

复制代码
package main

import (
	"fmt"
	"net"
	"net/rpc"
)

type Req struct {
	NumOne int
	NumTwo int
}

type Res struct {
	Num int
}

type Server struct{}

// RPC 方法签名要求:
// - 参数是结构体指针类型
// - 返回值是 error 类型
func (s *Server) Add(req *Req, res *Res) error {
	res.Num = req.NumOne + req.NumTwo
	return nil // 没有错误
}

func main() {
	server := new(Server)

	// 注册RPC方法
	err := rpc.Register(server)
	if err != nil {
		fmt.Println("Error registering:", err)
		return
	}

	// 启动监听并处理请求
	listen, err := net.Listen("tcp", ":8080")
	if err != nil {
		fmt.Println("Error starting server:", err)
		return
	}
	defer listen.Close()

	// 启动 HTTP 服务
	rpc.HandleHTTP()
	if err := http.Serve(listen, nil); err != nil {
		fmt.Println("Error serving:", err)
	}
}

总结:

  • 方法必须是导出的。

  • 方法的第一个参数是请求参数,必须是结构体(值类型或指针类型)。

  • 方法的第二个参数是响应参数,必须是指针类型。

  • 返回值是 error 类型,用于表示调用是否成功。

  • 方法调用是同步的,客户端会等待服务端完成后再返回结果。

相关推荐
GM_8287 小时前
从0开始在Go当中使用Apache Thrift框架(万字讲解+图文教程+详细代码)
rpc·go·apache·thrift
Kratos开源社区13 小时前
别卷 LangChain 了!Blades AI 框架让 Go 开发者轻松打造智能体
go·agent·ai编程
Kratos开源社区13 小时前
跟 Blades 学 Agent 设计 - 01 用“提示词链”让你的 AI 助手变身超级特工
llm·go·agent
百锦再20 小时前
第10章 错误处理
java·git·ai·rust·go·错误·pathon
Mgx2 天前
从 4.8 秒到 0.25 秒:我是如何把 Go 正则匹配提速 19 倍的?
go
遥天棋子3 天前
实战PaddleOCR自动识别车位坐标并渲染可点击按钮
go
久违 °3 天前
【安全开发】Nuclei源码分析-任务执行流程(三)
安全·网络安全·go
喵个咪3 天前
开箱即用的GO后台管理系统 Kratos Admin - 数据脱敏和隐私保护
后端·go·protobuf
shining3 天前
[Golang] 万字长文,一文入门go语言!
go
百锦再3 天前
第8章 模块系统
android·java·开发语言·python·ai·rust·go