面试题答案
一键面试RPC基本原理
- 定义:RPC 允许程序像调用本地函数一样调用不同地址空间(通常是不同机器)的函数,而无需显式处理网络通信细节。
- 原理步骤:
- 客户端存根(Stub):客户端调用本地的 RPC 函数(存根),这个函数看起来像本地函数调用,但实际上是为了发起远程调用做准备。它负责将调用的参数进行序列化(编组),生成网络消息。
- 网络传输:通过网络协议(如 TCP、UDP 等)将序列化后的消息发送到服务端。
- 服务端存根:服务端接收到网络消息后,由服务端存根进行反序列化(解组),还原出原始的调用参数。然后根据调用信息找到对应的本地函数进行调用。
- 结果返回:服务端本地函数执行完毕后,将结果返回给服务端存根,服务端存根再将结果序列化并通过网络发送回客户端。客户端存根接收到结果后进行反序列化,将结果返回给客户端调用者,就像本地函数调用返回一样。
使用Go标准库实现简单RPC服务端关键步骤
- 定义服务接口:
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 }
- 注册服务:
func main() { arith := new(Arith) rpc.Register(arith) }
- 监听和服务:
l, e := net.Listen("tcp", ":1234") if e!= nil { log.Fatal("listen error:", e) } for { conn, err := l.Accept() if err!= nil { log.Fatal("accept error:", err) } rpc.ServeConn(conn) }
使用Go标准库实现简单RPC客户端关键步骤
- 连接服务端:
client, err := rpc.Dial("tcp", "localhost:1234") if err!= nil { log.Fatal("dialing:", err) }
- 调用远程方法:
var reply int args := &Args{7, 8} 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)