什么是RPC?
RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。
1.GO语言中HTTPRPC调用:
RPC server:
package main
import (
"github.com/pkg/errors"
"net/rpc"
"net/http"
"fmt"
)
type Main int
type Args struct {
A int
B int
}
func (m *Main)Multiply(arg Args,reply *int) error{
*reply = arg.A * arg.B
fmt.Println("Multiply 被远程调用")
return nil
}
type Quotion struct {
Quo , Rem int
}
func (m *Main)Division(arg Args,quo *Quotion) error{
if arg.B == 0{
return errors.New("devide by zero")
}
quo.Quo = arg.A / arg.B
quo.Rem = arg.A % arg.B
fmt.Println("Division 被远程调用")
return nil
}
func main() {
main := new(Main)
rpc.Register(main)
rpc.HandleHTTP()
err := http.ListenAndServe(":1234",nil)
if err != nil{
fmt.Println(err.Error())
}
}
RPC Client
package main
import (
"flag"
//"net/http"
"net/rpc"
"fmt"
"runtime"
)
type Args struct {
A,B int
}
type Quotion struct {
Quo,Rem int
}
func main(){
var host string
flag.StringVar(&host,"host","127.0.0.1","目标主机")
flag.Parse()
client,err:= rpc.DialHTTP("tcp",host+":1234")
if err != nil{
_, file, line, _ :=runtime.Caller(0)
fmt.Println(err.Error(),file,line)
return
}
arg := &Args{5,5}
var reply int
err =client.Call("Main.Multiply",arg,&reply)
if err != nil{
_, file, line, _ :=runtime.Caller(0)
fmt.Println(err.Error(),file,line)
return
}
fmt.Printf("Multiply: %dx%d=%d\n",arg.A,arg.B,reply)
var que Quotion
err = client.Call("Main.Division",arg,&que)
if err != nil{
_, file, line, _ :=runtime.Caller(0)
fmt.Println(err.Error(),file,line)
return
}
fmt.Printf("Main.Division %d/%d=%d,%d%%%d=%d\n",arg.A,arg.B,que.Quo,arg.A,arg.B,que.Rem)
}
- 先启动服务端,再启动客户端,下面是输出结果:
//客户端输出结果:
Multiply: 5x5=25
Main.Division 5/5=1,5%5=0
服务端输出结果:
Multiply 被远程调用
Division 被远程调用
GO语言中TCPRPC调用:
RPC server:
tcprpc的server和httprpc的server相差不多,使用httprpc时rpc有直接调用即可,在tcp中rpc得自己先创建一个tcp服务端,创建之后将每次连接的conn传给传入rpc.ServeConn(conn)即可
package main
import (
"github.com/pkg/errors"
"net/rpc"
"fmt"
"net"
)
type Main int
type Args struct {
A int
B int
}
func (m *Main)Multiply(arg Args,reply *int) error{
*reply = arg.A * arg.B
fmt.Println("Multiply 被远程调用")
return nil
}
type Quotion struct {
Quo , Rem int
}
func (m *Main)Division(arg Args,quo *Quotion) error{
if arg.B == 0{
return errors.New("devide by zero")
}
quo.Quo = arg.A / arg.B
quo.Rem = arg.A % arg.B
fmt.Println("Division 被远程调用")
return nil
}
func main(){
main := new(Main)
rpc.Register(main)
tcpAddr ,err:= net.ResolveTCPAddr("tcp",":1234")
if err != nil{
fmt.Println(err)
return
}
listen,err := net.ListenTCP("tcp",tcpAddr)
if err != nil{
fmt.Println(err)
return
}
for{
conn,err := listen.Accept()
if err !=nil{
fmt.Println(err)
continue
}
//只需要将连接句柄传入rpc包会自动解析
rpc.ServeConn(conn)
}
}
RPC 客户端和HTTPRPC客户端基本一样只需将下面代码修改即可
RPC Client
//将创建客户端从DialHTTP改为Dial即可
client,err:= rpc.Dial("tcp",host+":1234")
输出结果和上面一样
GO语言中JSONRPC调用:
RPC server:
//只需要代码中引入"net/rpc/jsonrpc"包,把下面这行代码修改即可
jsonrpc.ServeConn(conn)
RPC client:
//只需要代码中引入"net/rpc/jsonrpc"包,把下面这行代码修改即可
client,err:= jsonrpc.Dial("tcp",host+":1234")