首先在golang实现rpc方法一net/rpc库中实现了RPC方法,但是那个方法不是跨平台的,没法在其他语言中调用这个实现的RPC方法,接下来我们可以通过jsonroc库实现跨语言的RPC方法。俩种实现方式的代码其实也是差不多的,大差不差,只是调用的库不同。
项目左侧包结构
rpc服务端
serverrpc.go实现代码如下
Go
package main
import (
"errors"
"fmt"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"os"
)
// 运算结构体
type Arith struct {
}
// 运算请求结构体
type ArithRequest struct {
A int
B int
}
// 运算响应结构体
type ArithResponse struct {
Pro int //product 表示乘积
Quo int //quotient 表示商
Rem int //remaind 表示余数
}
/*
运算结构体的乘法运算方法
第一个参数只需要拿到其里面的值只需要传一个结构体即可,
第二个参数需要将运算结果存到其里面所以需要传地址
*/
func (this *Arith) Multiply(req ArithRequest, res *ArithResponse) error {
res.Pro = req.A * req.B
return nil
}
/*
运算结构体的除法运算方法
第一个参数只需要拿到其里面的值只需要传一个结构体即可,
第二个参数需要将运算结果存到其里面所以需要传地址
*/
func (this *Arith) Divide(req ArithRequest, res *ArithResponse) error {
if req.B == 0 { //除法为0,运算不合法
return errors.New("divide by zero")
}
res.Quo = req.A / req.B
res.Rem = req.A % req.B
return nil
}
func main() {
rpc.Register(new(Arith)) //注册rpc服务
lis, err := net.Listen("tcp", "127.0.0.1:8090") //Listen是block(阻塞的)
if err != nil {
log.Fatalln("fatal error:", err)
}
fmt.Fprintf(os.Stdout, "%s", "start connection")
//写了一个循环里面启动了一个协程可以处理多个协程
for {
conn, err := lis.Accept() //接收客户端连接请求
if err != nil { //当前请求存在错误,跳过当前请求
continue
}
//启动一个协程并发处理请求
go func(conn net.Conn) {
fmt.Fprintf(os.Stdout, "%s", "new client is coming\n")
jsonrpc.ServeConn(conn)
}(conn) //自己调用自己
}
}
rpc客户端
clientrpc.go实现代码如下
Go
package main
import (
"fmt"
"log"
"net/rpc/jsonrpc"
)
// 算数运算请求结构体
type ArithRequest struct {
A int
B int
}
// 算数运算响应结构体
type ArithResponse struct {
Pro int //product 乘积
Quo int //quotient 商
Rem int //remain 余数
}
func main() {
//通过jsonrpc库实现
conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8090")
if err != nil {
log.Fatalln("dailing error", err)
}
req := ArithRequest{9, 2} //请求结构体
var res ArithResponse //响应结构体,用于存储运算结果
//实现jsonrpc之后,通过Call方法在客户端调用服务端里面算数运算结构体的乘法运算方法
err = conn.Call("Arith.Multiply", req, &res)
if err != nil {
log.Fatalln("arith error", err)
}
fmt.Printf("%d * %d = %d\n", req.A, req.B, res.Pro)
//实现jsonrpc之后,通过Call方法在客户端调用服务端里面算数运算结构体的除法运算方法
err = conn.Call("Arith.Divide", req, &res)
if err != nil {
log.Fatalln("arith error", err)
}
fmt.Printf("%d / %d, quo is %d, rem is %d\n", req.A, req.B, res.Quo, res.Rem)
}
详细实现步骤
1.首先初始化项目
bash
go mod init pro01 //pro01表示项目名称
2.在当前项目下新建包server,并且在该包下面新建serverrpc.go实现rpc服务端
3.在当前项目下新建包client,并且在该包下面新建clientrpc.go实现rpc客户端
4.运行rpc服务端程序 ,首先进入server包,然后运行serverrpc.go
bash
cd server
go run serverrpc.go
5.运行rpc客户端程序,首先进入client包,然后运行clientrpc.go
bash
cd client
go run clientrpc.go
6.查看输出结果是否正确,输出结果如下表示程序运行结果正确,当然我这里的结果是根据我在请求结构体里面给出的俩个数值进行计算的,具体结果是否正确根据自己的具体程序判断。
常见错误
如果启动rpc服务时出现了如下图所示错误,说明在之前已经启动过rpc服务,并且没有关闭,导致端口被占用了,只需要把之前启动的程序停掉,然后重新启动rpc服务即可。
总结:
jsonrpc库和net/rpc都实现了rpc方法,实现了远程进程调用,区别在于net/rpc是不跨平台的,别的语言没法调用,而jsonrpc是跨平台的,别的语言也可以调用rpc方法。