RPC
Remote Procedure Call Protocol —— 远程过程调用协议!
IPC: 进程间通信
RPC:远程进通信 —— 应用层协议(http协议同层)。底层使用 TCP 实现。
像调用本地函数一样,去调用远程函数
通过rpc协议,传递:函数名、函数参数。达到在本地,调用远端函数,得返回值到本地的目标。
对比:
socket通信
server端:
net.Listen() —— listener 创建监听器
listener.Accpet() —— conn 启动监听,建立连接
conn.Read()
conn.Write()
defer conn.Close() / listener.Close()
client端:
net.Dial() —— conn
conn.Write()
conn.Read()
defer conn.Close()
RPC 步骤
---- 服务端:
注册 rpc 服务对象。给对象绑定方法( 1. 定义类, 2. 绑定类方法 )
rpc.RegisterName("服务名",回调对象)
创建监听器
listener, err := net.Listen()
建立连接
conn, err := listener.Accept()
将连接 绑定 rpc 服务。
rpc.ServeConn(conn)
---- 客户端:
用 rpc 连接服务器。
conn, err := rpc.Dial()
调用远程函数。
conn.Call("服务名.方法名", 传入参数, 传出参数)
RPC相关函数
注册 rpc 服务
func (server *Server) RegisterName(name string, rcvr interface{}) error
参数1:服务名。字符串类型
参数2:对应的rpc对象。该对象绑定的方法要满足:
方法必须是包外可见,即首字母大写。
方法有两个参数,都i是导出类型(strcut、自定义切片之类的)、内建类型
方法的第二个参数,必须为指针(传出参数)
方法只有一个error接口类型的 返回值
举例:
type ZZT stuct {
}
func (this *ZZT) HelloZZT (name string, resp *string) error {
}
rpc.RegisterName("服务名,什么都可以", new(ZZT))
绑定rpc服务
func (server *Server) ServeConn(conn io.ReadWriteCloser)
conn: 成功建立好连接的 socket —— conn
调用远程函数
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
serviceMethod: “服务名.方法名”
args: 传入参数。 方法需要的数据。
reply: 传出参数。定义 var 变量,&变量名 完成传参。
简易实现:
package main
import (
"fmt"
"net"
"net/rpc"
)
//定义类对象
type Fy struct {
}
//类方法
func (this *Fy) HelloWorld(name string, resp *string) error {
*resp = name + "你好吖"
return nil
}
func main() {
//注册RPC服务,绑定对象方法
err := rpc.RegisterName("ZZT", new(Fy))
if err != nil {
fmt.Println("RPC服务注册失败")
return
}
//设置监听
listener, err := net.Listen("tcp", "127.0.0.1:9876")
if err != nil {
fmt.Println("Listen err:", err)
return
}
fmt.Println("开始监听")
defer listener.Close()
//建立连接
conn, err := listener.Accept()
if err != nil {
fmt.Println("Accept err:", err)
return
}
fmt.Println("建立连接")
defer conn.Close()
//绑定服务
rpc.ServeConn(conn)
fmt.Println("服务绑定")
}
package main
import (
"fmt"
"net/rpc"
)
func main() {
//用rpc连接服务器
conn, err := rpc.Dial("tcp", "127.0.0.1:9876")
if err != nil {
fmt.Println("Dial err:", err)
return
}
fmt.Println("连接上服务器")
//调用远程函数(服务名.方法名)
var reply string
err = conn.Call("ZZT.HelloWorld", "奥里给", &reply)
if err != nil {
fmt.Println("Call err ", err)
return
}
fmt.Println(reply)
}
rpc 封装
服务端封装
// 定义接口 type xxx interface { 方法名(传入参数,传出参数) error } 例: type MyInterface interface { HelloWorld(string, *string) error }
// 封装注册服务方法 func RegisterService (i MyInterface) { rpc.RegisterName("hello", i) }
客户端封装
// 定义类 type MyClient struct { c *rpc.Client }
// 绑定类方法 func (this *MyClient)HelloWorld(a string, b *string) error { return this.c.Call("hello.HelloWorld", a, b) }
// 初始客户端 func InitClient(addr string) error { conn, _ := jsonrpc.Dial("tcp", adddr) return MyClient{c:conn} }
笔记参考
版权声明:本文为weixin_46367157原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。