如何在 Go 中使用 net/rpc
包实现一个简单的 RPC 服务。
1. 定义服务
首先,我们需要定义一个服务。这个服务包含一个结构体和一些方法。这些方法将被暴露给客户端调用。
package main
import (
"errors"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"log"
)
// 定义一个结构体,用于实现服务的方法
type Arith int
// 定义一个参数结构体
type Args struct {
A, B int
}
// 定义一个结果结构体
type Quotient struct {
Quo, Rem int
}
// 定义一个方法,用于乘法运算
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
// 定义一个方法,用于除法运算
func (t *Arith) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
2. 注册服务
接下来,我们需要注册这个服务,使其可以被客户端调用。
func main() {
arith := new(Arith)
rpc.Register(arith)
listener, err := net.Listen("tcp", ":1234")
if err != nil {
log.Fatal("ListenTCP error:", err)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal("Accept error:", err)
}
go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
}
}
3. 客户端调用
最后,我们编写客户端代码来调用这个服务。
package main
import (
"fmt"
"net"
"net/rpc/jsonrpc"
"log"
)
func main() {
conn, err := net.Dial("tcp", "localhost:1234")
if err != nil {
log.Fatal("Dialing:", err)
}
defer conn.Close()
client := jsonrpc.NewClient(conn)
// 调用 Multiply 方法
args := &Args{7, 8}
var reply int
err = client.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("Arith error:", err)
}
fmt.Printf("Arith: %d*%d=%d\n", args.A, args.B, reply)
// 调用 Divide 方法
args = &Args{15, 6}
var quo Quotient
err = client.Call("Arith.Divide", args, &quo)
if err != nil {
log.Fatal("Arith error:", err)
}
fmt.Printf("Arith: %d/%d=%d remainder %d\n", args.A, args.B, quo.Quo, quo.Rem)
}
运行示例
- 首先运行服务器代码:
go run server.go
- 然后运行客户端代码:
go run client.go
客户端将输出:
Arith: 7*8=56
Arith: 15/6=2 remainder 3