go语言--RPC

golang中的rpc

• RPC定义

RPC,Remote Procedure Call Protocol,远程过程调用协议。RPC是一种通过网络从远程计算机程序上请求服务,但不需要了解底层网络技术的一种协议。RPC协议基于某些传输协议(如TCP和UDP协议等)而存在,为通信程序之间携带信息数据。

在传统计算机编程语言中,譬如C和C++,实现RPC是一件不容易的事情。为了实现RPC,首先得基于不同的操作系统提供的网络模型实现网络通信,然后需要自己封装协议来实现RPC,通常为了方便使用还结合使用Lua进行脚本调用。而golang语言原生支持RPC,极大地提高了开发效率。

·
·
·

• net/rpc包

在golang中,标准库提供的net/rpc包实现了RPC协议的相关细节,开发者可以方便地使用该包编写出RPC服务端和客户端程序,这使得用golang开发多个进程之间通信变得非常简单。

官网介绍:rpc包提供了基于网络或其他I/O连接来访问某个对象的导出函数的方法。服务端需要注册提供RPC服务的对象,并以该对象类型的名称作为可见的服务名。对象注册完成之后,该对象的导出函数将可以被远程访问。服务端可以注册多个不同类型的对象作为服务,但是需要注意的是,注册同一类型的多个对象将引发错误。
·
·
·

导出函数需满足的条件

• 函数的类型需要导出。
• 函数需要导出。
• 函数必须拥有两个参数,参数必须是导出类型或内建类型。
• 函数的第二个参数必须是一个指针。
• 函数必须返回一个error类型的值。

满足上述条件的函数可以简单表示成:
在这里插入图片描述

• 类型T、T1和T2默认使用golang内置的encoding/gob包进行编码解码。
• 第一个参数argType表示由RPC客户端传入的参数。
• 第二个参数replyType表示要返回给RPC客户端的结果。
• 函数最后返回一个error类型的值。如果一个error值返回,replyType参数将不会发送给RPC客户端,而error值将会作为一个字符串发送给RPC客户端。

·
·
·

下面给出一个实例并且分析各个的作用

服务端代码:

packagemain
 
import(
"errors"
"log"
"net"
"net/http"
"net/rpc"
"time"
)
 
typeArgsstruct{
A,Bint
}
 
typeQuotientstruct{
Quo,Remint
}
 
typeArithint
 
func(t*Arith)Multiply(args*Args,reply*int)error{
*reply=args.A*args.B
returnnil
}
 
func(t*Arith)Divide(args*Args,quo*Quotient)error{
ifargs.B==0{
returnerrors.New("dividebyzero")
}
 
quo.Quo=args.A/args.B
quo.Rem=args.A%args.B
returnnil
}
 
funcmain(){
arith:=new(Arith)
rpc.Register(arith)
rpc.HandleHTTP()
 
l,e:=net.Listen("tcp",":1234")
deferl.Close()
 
ife!=nil{
log.Fatal("listenerror:",e)
return
}
 
gohttp.Serve(l,nil)
log.Println("rpcserverstarted!")
 
for{
time.Sleep(1*time.Second)
}
}

客户端代码:

packagemain
 
import(
"log"
"net/rpc"
)
 
typeArgsstruct{
A,Bint
}
 
typeQuotientstruct{
Quo,Remint
}
 
funcmain(){
client,err:=rpc.DialHTTP("tcp","127.0.0.1:1234")
deferclient.Close()
 
iferr!=nil{
log.Fatal("dialingerror:",err)
return
}
 
args1:=&Args{2,3}
args2:=&Args{7,2}
args3:=&Args{7,0}
 
reply1:=0
reply2:=Quotient{}
reply3:=Quotient{}
 
err=client.Call("Arith.Multiply",args1,&reply1)
iferr!=nil{
log.Fatal("Aritherror:",err)
return
 
}
log.Println(reply1)//6
 
err=client.Call("Arith.Divide",args2,&reply2)
iferr!=nil{
log.Fatal("Aritherror:",err)
return
 
}
log.Println(reply2)//{31}
 
err=client.Call("Arith.Divide",args3,&reply3)
iferr!=nil{
log.Fatal("Aritherror:",err)//aritherror:dividebyzero
return
 
}
log.Println(reply3)
}
 

测试结果: 在这里插入图片描述
如上图所示,再客户端中成功将传递给服务端的参数按照服务端的方法计算出了结果。
·
·
·

下面开始分析各个步骤的具体作用

服务端
在这里插入图片描述
图中所指示的是rpc必要的包

在这里插入图片描述
如中两个定义的结构体是因为实验需要而定义的,当然也可以是其他形式的,这个的(1)是客户端用来向服务端传递数据的,(2)是服务端将计算后的结果返回给客户端的。

在这里插入图片描述
自己重新定义一个
在这里插入图片描述

如中的(1)就是客户端传递进来的参数,(2)就是服务端将要返回给客户端的参数
如果是刚刚开始学golang这里介绍一下这个方法:
方法相对于函数:函数称之为函数在go里面,我的理解是只能够通过直接调用,而方法区别于函数,只能通过特定的对象“应该是这么称之为把,还是称之为结构体把”引用才能实现。实例如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
就如上图所示的之后方法才可以通过指定的结构体引用,而且在传递值的类型必须选用指针类型。
在这里插入图片描述
客户端:
在这里插入图片描述
在这里插入图片描述
如果学过python网络编程的可以类比一下。

发布了44 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42224330/article/details/104487559