RPC介绍
远程过程调用(Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。 该协议允许运行于一台计算机的程序调用另一台计算机的程序,而程序员无需额外地为这个交互作用编程。 如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。用通俗易懂的语言描述就是:RPC允许跨机器、跨语言调用计算机程序方法。
RPC是一种通讯网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
RPC是远程过程调用,其调用协议通常包括序列化协议和传输协议,序列化协议有基于传统文本的xml和json,二进制编码的Protobuf和Hessian。传输协议是指其底层网络传输所使用的协议,比如TCP、HTTP。
Golang使用RPC
Go自带rpc库
示例1 使用net/rpc库
rpc_server.go
package main
import (
"errors"
"net/rpc"
"net"
"log"
"fmt"
"os"
"net/http"
)
//算术运算结构体
type Arith struct {
}
//算数运算请求结构体
type ArithRequest struct {
A int
B int
}
//算术运算响应结构体
type ArithResponse struct {
Pro int //乘积
Quo int //商
Rem int //余数
}
//乘法运算
func (a *Arith) Multiply(req *ArithRequest, res *ArithResponse) error {
res.Pro = req.A * req.B
return nil
}
//除法运算
func (a *Arith) Divide(req *ArithRequest, res *ArithResponse) error {
if req.B == 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服务
rpc.HandleHTTP() //采用http协议作为rpc通讯协议
lis,err := net.Listen("tcp",":8095")
if err != nil {
log.Fatal("listen error:",err)
}
fmt.Fprintf(os.Stdout,"%s","start connection")
http.Serve(lis,nil)
}
rpc_client.go
package main
import (
"net/rpc"
"log"
"fmt"
)
//算数运算请求结构体
type ArithRequest struct {
A int
B int
}
//算术运算响应结构体
type ArithResponse struct {
Pro int //乘积
Quo int //商
Rem int //余数
}
func main() {
conn,err := rpc.DialHTTP("tcp","127.0.0.1:8095")
if err != nil {
log.Fatalln("dailing error:",err)
}
req := ArithRequest{9,2}
var res ArithResponse
//
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)
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)
}
示例二 使用net/rpc/jsonrpc
rpc_json_server.go
package main
import (
"errors"
"net/rpc"
"net"
"log"
"fmt"
"os"
"net/rpc/jsonrpc"
)
//算术运算结构体
type Arith struct {
}
//算数运算请求结构体
type ArithRequest struct {
A int
B int
}
//算术运算响应结构体
type ArithResponse struct {
Pro int //乘积
Quo int //商
Rem int //余数
}
//乘法运算
func (a *Arith) Multiply(req *ArithRequest, res *ArithResponse) error {
res.Pro = req.A * req.B
return nil
}
//除法运算
func (a *Arith) Divide(req *ArithRequest, res *ArithResponse) error {
if req.B == 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",":8096")
if err != nil {
log.Fatal("listen error:",err)
}
fmt.Fprintf(os.Stdout,"%s","start connection")
for {
conn,err := lis.Accept() //接受客户端的连接
if err != nil {
continue
}
fmt.Printf("receive client connect %s \n",conn.RemoteAddr())
go func(conn net.Conn) {
fmt.Fprintf(os.Stdout,"%s","new client is coming \n")
jsonrpc.ServeConn(conn)
}(conn)
}
}
rpc_json_client.go
package main
import (
"log"
"fmt"
"net/rpc/jsonrpc"
)
//算数运算请求结构体
type ArithRequest struct {
A int
B int
}
//算术运算响应结构体
type ArithResponse struct {
Pro int //乘积
Quo int //商
Rem int //余数
}
func main() {
conn,err := jsonrpc.Dial("tcp","127.0.0.1:8096")
if err != nil {
log.Fatalln("dailing error:",err)
}
req := ArithRequest{9,2}
var res ArithResponse
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)
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)
}
golang自带的RPC库只提供了一些简单的功能,如果想要在微服务框架中使用RPC,最好使用RPC框架
Golang常用的RPC库有gRPC、RPCX等