rpc是什么
RPC(Remote Procedure Call)是远程过程调用,通俗的说就是调用远处的一个函数。
入门
一. RPC版 HelloWorld
服务端代码
type HelloWorldService struct {
}
func (hello *HelloWorldService) Hello(request string, reply *string) error {
*reply = "recieved msg :" + request + "\n"
return nil
}
func Run() {
rpc.RegisterName("HelloService", new(HelloWorldService))
listen, err := net.Listen("tcp", "127.0.0.1:9090")
if err != nil {
log.Fatalln(err)
}
conn, err := listen.Accept()
if err != nil {
log.Fatalln(err)
}
rpc.ServeConn(conn)
}
说明:rpc.RegisterName
会将HelloWorldService
对象中所有满足rpc
规则的方法注册为rpc
函数,并放在HelloService
服务空间之下。其中Hello
方法必须满足以下规则:
- 访问限制必须公开
- 只能有2个序列化参数,第二个参数必须是指针类型
- 返回
error
类型
客户端代码:
func main() {
client, err := rpc.Dial("tcp", "127.0.0.1:9090")
if err !=nil {
log.Fatalln(err)
}
var reply string
err = client.Call("HelloService.Hello", "Hello World", &reply)
if err !=nil {
log.Fatalln(err)
}
fmt.Println(reply)
}
首先通过rpc.Dial
拨号rpc
服务,cient.Call()
可理解为呼叫,其第一个参数是rpc
的服务服务名和方法名,第二和第三个参数是该方法的2个参数。
二. 更安全的RPC接口
在设计RPC的应用中,作为开发人员至少有3中角色:
- 服务器端实现
RPC
方法的开发人员 - 客户端调用
RPC
方法的开发人员 - 制定服务端和客户端
RPC
接口规范的设计人员
上面HelloWorld的例子虽然看似简单,但是不利于后期的维护和工作的切割,其中存在一个较大的问题是:
客户端中,Call()
方法的参数无法得到编译器安全检查,只有运行时才能发现错误。
服务端代码:
- 接口定义
const HelloServiceName = "study.rpc.HelloService"
type HelloServiceInterface interface {
Hello(request string,reply *string) error
}
func RegisterHelloService(srv HelloServiceInterface) error {
return rpc.RegisterName(HelloServiceName,srv)
}
- 服务端代码
type HelloWorldService struct {
}
func (hello *HelloWorldService) Hello(request string, reply *string) error {
*reply = "recieved msg :" + request + "\n"
return nil
}
func main() {
RegisterHelloService(new(HelloWorldService))
listen, err := net.Listen("tcp", "127.0.0.1:9090")
if err != nil {
log.Fatalln(err)
}
for {
conn, err := listen.Accept()
if err != nil {
log.Fatalln(err)
}
go rpc.ServeConn(conn)
}
}
- 客户端代码
type HelloServiceClient struct {
*rpc.Client
}
//检测HelloServiceClient 是否实现了 HelloServiceInterface
var _ HelloServiceInterface = (*HelloServiceClient)(nil)
func (client *HelloServiceClient) Hello(request string, reply *string) error {
return client.Call(HelloServiceName+".Hello",request,reply)
}
func DialHelloService(network string,addr string) (*HelloServiceClient,error) {
client, err := rpc.Dial(network, addr)
if err !=nil {
return nil,err
}
return &HelloServiceClient{client},nil
}
func main() {
service, err := DialHelloService("tcp", "127.0.0.1:9090")
if err !=nil {
log.Fatalln(err)
}
var reply string
err = service.Hello("Hello world", &reply)
if err !=nil {
log.Fatalln(err)
}
fmt.Println(reply)
}
网友评论