Go语言从入门到规范-6.6、Go语言rpc包

网友投稿 908 2022-11-18

Go语言从入门到规范-6.6、Go语言rpc包

Go语言从入门到规范-6.6、Go语言rpc包

Go语言从入门到规范-6.6、Go语言rpc包

文章目录

​​Go语言从入门到规范-6.6、Go语言rpc包​​

​​1. 前言​​​​2. 概述​​

​​(1). rpc概述​​​​(2). 流程​​​​(3). Go rpc包概述​​

​​3. 常量​​​​4. 变量​​​​5. func [Accept](func [HandleHTTP](func [Register](func [RegisterName](func [ServeCodec](func [ServeConn](func [ServeRequest](type [Call](type [Client](func [Dial](func [DialHTTP](func [DialHTTPPath](func [NewClient](func [NewClientWithCodec](func (*Client) [Call](func (*Client) [Close](func (*Client) [Go](type [ClientCodec](type [Request](type [Response](type [Server](func [NewServer](func (*Server) [Accept](func (*Server) [HandleHTTP](func (*Server) [Register](func (*Server) [RegisterName](func (*Server) [ServeCodec](func (*Server) [ServeConn](func (*Server) [ServeHTTP](func (*Server) [ServeRequest](type [ServerCodec](type [ServerError](func (ServerError) [Error](前言

在分布式计算、微服务大行其道的当下,我们需要对rpc进行了解学习,而且很有必要掌握该技术,我们先对rpc的概念做简单了解,然后总结一下go的rpc包,然后写一个示例来熟悉rpc协议。

2. 概述

(1). rpc概述

​​在分布式计算,远程过程调用(英语:Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。​​该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。RPC是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求-接受回应进行信息交互的系统。

​​如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用​​,例:Java RMI。

​​RPC是一种进程间通信的模式,程序分布在不同的地址空间里。​​如果在同一主机里,RPC可以通过不同的虚拟地址空间(即便使用相同的物理地址)进行通讯,而在不同的主机间,则通过不同的物理地址进行交互。许多技术(常常是不兼容)都是基于这种概念而实现的。

(2). 流程

1、客户端调用客户端stub(client stub)。这个调用是在本地,并将调用参数push到栈(stack)中。2、客户端stub(client stub)将这些参数包装,并通过系统调用发送到服务端机器。打包的过程叫 marshalling。(常见方式:XML、JSON、二进制编码)3、客户端本地操作系统发送信息至服务器。(可通过自定义TCP协议或HTTP传输) 服务器系统将信息传送至服务端stub(server stub)。4、服务端stub(server stub)解析信息。该过程叫 unmarshalling。5、服务端stub(server stub)调用程序,并通过类似的方式返回给客户端。

为了允许不同的客户端均能访问服务器,许多标准化的 RPC 系统应运而生了。其中大部分采用接口描述语言(Interface Description Language,IDL),方便跨平台的远程过程调用。

(3). Go rpc包概述

rpc 包提供了一个方法来通过网络或者其他的I/O连接进入对象的外部方法. 一个server注册一个对象, 标记它成为可见对象类型名字的服务。注册后,对象的外部方法就可以远程调用了。一个server可以注册多个 不同类型的对象,但是却不可以注册多个相同类型的对象。

只有满足这些标准的方法才会被远程调用视为可见;其他的方法都会被忽略:

- 方法是外部可见的。- 方法有两个参数,参数的类型都是外部可见的。- 方法的第二个参数是一个指针。- 方法有返回类型错误

事实上,方法必须看起来类似这样

func (t *T) MethodName(argType T1, replyType *T2) error

T,T1和T2可以被encoding/gob序列化。 不管使用什么编解码,这些要求都要满足。(在未来,这些要求可能对自定义的编解码会放宽)

方法的第一个参数代表调用者提供的参数;第二个参数代表返回给调用者的参数。方法的返回值,如果是非空的话 就会被作为一个string返回,客户端会error像是被errors.New调用返回的一样。如果error返回的话, 返回的参数将会被送回给客户端。

服务断可以使用ServeConn来处理单个连接上的请求。更通用的方法,服务器可以制造一个网络监听,然后调用 Accept,或者对一个HTTP监听,处理HandleHTTP和来建立一个新的网络连接(一个HTTP连接)。客户端获得到的对象有两个方法,Call和Go,指定的参数有:服务和方法指向参数的指针,接受返回结果的指针。

call方法等待远程调用完成,但Go方法是异步调用call方法,使用Call通道来标志调用完成。

除非有明确制定编解码器,否则默认使用encoding/gob来传输数据。

这是个简单的例子,服务器希望对外服务出Arith对象:

package servertype Args struct { A, B int}type Quotient struct { Quo, Rem int}type Arith intfunc (t *Arith) Multiply(args *Args, reply *int) error { *reply = args.A * args.B return nil}func (t *Arith) Divide(args *Args, quo *Quotient) error { if args.B == 0 { return errors.New("divide by zero") } quo.Quo = args.A / args.B quo.Rem = args.A % args.B return nil}

服务端调用(使用HTTP服务):

arith := new(Arith)rpc.Register(arith)rpc.HandleHTTP()l, e := net.Listen("tcp", ":1234")if e != nil { log.Fatal("listen error:", e)}go nil)

在这个时候,客户端可以看见服务“Arith”,并且有“Arith.Multiply”方法和“Arith.Divide”方法。 调用其中一个,客户端首先连接服务:

client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")if err != nil { log.Fatal("dialing:", err)}

当它要调用远程服务的时候:

// Synchronous callargs := &server.Args{7,8}var reply interr = client.Call("Arith.Multiply", args, &reply)if err != nil { log.Fatal("arith error:", err)}fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)

or

// Asynchronous callquotient := new(Quotient)divCall := client.Go("Arith.Divide", args, quotient, nil)replyCall := <-divCall.Done // will be equal to divCall// check errors, print, etc.

服务端的实现需要为客户端提供一个简单的,类型安全服务。

3. 常量

const ( // Defaults used by HandleHTTP //默认被HandleHTPP使用 DefaultRPCPath = "/_goRPC_" DefaultDebugPath = "/debug/rpc")

4. 变量

var DefaultServer = NewServer()

DefaultServer是默认的*Server实例。

var ErrShutdown = errors.New("connection is shut down")

5. func ​​Accept​​

func Accept(lis net.Listener)

Accept在连接上监听和服务请求,为每个连接调用DefaultServer。 Accept是阻塞的,调用者一般是在go语句中调用。

6. func ​​HandleHTTP​​

func HandleHTTP()

HandleHTTP在DefaultRPCPath上为RPC消息注册了一个HTTP的处理器到DefaultServer上,并且在 DefaultDebugPath上注册了一个debuggin处理器。 它仍然需要调用func ​​Register​​

func Register(rcvr interface{}) error

Register在DefaultServer中发布接收者的方法

8. func ​​RegisterName​​

func RegisterName(name string, rcvr interface{}) error

RegisterName就像Register,但是为类型使用自定义的名字而不是接收者定义的名字。

9. func ​​ServeCodec​​

func ServeCodec(codec ServerCodec)

ServeCodec和ServeConn一样,但是使用特定的codec来解码请求,编码回复。

10. func ​​ServeConn​​

func ServeConn(conn io.ReadWriteCloser)

ServeConn在单个连接上调用DefaultServer。 ServeConn阻塞,服务连接,直到客户端关闭。 调用者一般在go语句中调用ServeConn。ServeConn在连接上使用gob格式(参考gob包)。 要使用自定义的编解码,使用ServeCodec.

11. func ​​ServeRequest​​

func ServeRequest(codec ServerCodec) error

ServeRequest和ServeCodec相似,但是同步地服务单个请求。 它直到完成了才关闭codec。

12. type ​​Call​​

type Call struct { ServiceMethod string // The name of the service and method to call. // 要调用的服务名字和方法 Args interface{} // The argument to the function (*struct). // 方法的参数(*struct) Reply interface{} // The reply from the function (*struct). // 方法的返回值(*struct) Error error // After completion, the error status. // 完成之后返回的error Done chan *Call // Strobes when call is complete. // 调用完成的信号}

Call 代表一个活跃的RPC

13. type ​​Client​​

type Client struct { // contains filtered or unexported fields}

Client代表一个RPC客户端。 一个客户端可以有多个调用,并且一个客户端可以被多个goroutine同时使用

(1). func ​​Dial​​

func Dial(network, address string) (*Client, error)

Dial根据指定的网络地址连接到一个RPC服务。

(2). func ​​DialHTTP​​

func DialHTTP(network, address string) (*Client, error)

DialHttp根据制定的网络地址,连接到一个HTTP RPC服务。并且在默认的HTTP RPC路径进行监听。

(3). func ​​DialHTTPPath​​

func DialHTTPPath(network, address, path string) (*Client, error)

DialHTTPPATH根据制定的网络地址和路径连接到一个HTTP RPC服务。

(4). func ​​NewClient​​

func NewClient(conn io.ReadWriteCloser) *Client

NewClient返回一个新的客户端来处理对连接另一端的一组服务的请求。它在连接的写端添加一个缓冲区,以便将报头和有效负载作为一个单元发送

(5). func ​​NewClientWithCodec​​

func NewClientWithCodec(codec ClientCodec) *Client

NewClientWithCodec与NewClient类似,但使用指定的编解码器对请求进行编码并解码响应。

(6). func (*Client) ​​Call​​

func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error

Call调用方法的名字,等待它完成,然后返回成功或失败的error状态。

(7). func (*Client) ​​Close​​

func (client *Client) Close() error

(8). func (*Client) ​​Go​​

func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call

Go能异步调用功能。它返回Call结构来代表回调。当调用完成,返回相同的Call对象,done channel就会获取到 信息。如果done是空的话,Go就会分配一个新的channel。如果非空的话,done必须缓冲起来,或者Go会立即崩溃。

14. type ​​ClientCodec​​

type ClientCodec interface { // WriteRequest must be safe for concurrent use by multiple goroutines. WriteRequest(*Request, interface{}) error ReadResponseHeader(*Response) error ReadResponseBody(interface{}) error Close() error}

ClientCodec实现了客户端一方对RPC会话的写RPC请求,和读RPC回复功能。客户端调用WriterRequest 往连接中写RPC请求,同时调用ReadResponseHeader和ReadResponseBody来读取RPC返回。当结束连接的时候 客户端调用Close。ReadResponseBody可以使用一个nil参数,来读取RPC回复,然后丢弃信息。

15. type ​​Request​​

type Request struct { ServiceMethod string // format: "Service.Method" // 格式:“Service.Method” Seq uint64 // sequence number chosen by client // 客户端序列化的数 // contains filtered or unexported fields}

Request是在每个RPC调用之前使用的header。它是内部使用的,写在这里是为了调试用,例如分析网络的流量等。

16. type ​​Response​​

type Response struct { ServiceMethod string // echoes that of the Request // 每个Request的相应方法 Seq uint64 // echoes that of the request // 每个request的相应 Error string // error, if any. // 如果有的话,表示错误 // contains filtered or unexported fields}

Response是在每个RPC回复之前被写在头里面的。它是内部使用的,写在这里是为了调试用,例如分析网络的流量等。

17. type ​​Server​​

type Server struct { // contains filtered or unexported fields}

Server代表一个RPC服务。

(1). func ​​NewServer​​

func NewServer() *Server

NewServer返回一个新的Server

(2). func (*Server) ​​Accept​​

func (server *Server) Accept(lis net.Listener)

Accept接收连接,为每个连接监听和服务请求。Accept是阻塞的,调用者一般在go语句中使用它。

(3). func (*Server) ​​HandleHTTP​​

func (server *Server) HandleHTTP(rpcPath, debugPath string)

HandleHTTP在rpcPath上为RPC消息注册一个HTTP处理器,并在debugPath注册一个debugging处理器。 它仍然需要调用func (*Server) ​​Register​​

func (server *Server) Register(rcvr interface{}) error

Register发布服务器的一系列方法,接受器必须满足这几个条件:

- 对外可见的方法- 两个参数,都指向对外可见的结构- 一个error类型返回值

如果接收者不是一个对外可见的类型,或者没有任何方法,或者没有满足条件的方法,都会返回error。 它也会使用log包来记录错误。客户端进入每个方法使用字符串格式形如“Type.Method”, 这里Type是接收者的具体的类型。

(5). func (*Server) ​​RegisterName​​

func (server *Server) RegisterName(name string, rcvr interface{}) error

RegisterName像Register,但是为type使用提供的名字,而不是使用receivers的具体类型。

(6). func (*Server) ​​ServeCodec​​

func (server *Server) ServeCodec(codec ServerCodec)

ServerCodec和ServeConn相似,但是使用自定义的编解码器来解码请求和编码回复。

(7). func (*Server) ​​ServeConn​​

func (server *Server) ServeConn(conn io.ReadWriteCloser)

ServeConn在单个连接上跑server。 ServeConn阻塞,知道客户端关闭之后才继续服务其他连接。 调用者一般在go语句中调用ServeConn。 ServeConn在连接传输的时候使用gob格式(参考gob包)。可以使用自定义编码器,ServeCodec。

(8). func (*Server) ​​ServeHTTP​​

func (server *Server) ServeHTTP(w req *func (*Server) ​​ServeRequest​​

func (server *Server) ServeRequest(codec ServerCodec) error

ServerRequest和ServeCodec相似,但是是同步地服务单个请求。 它在结束的时候不会关闭编解码器。

18. type ​​ServerCodec​​

type ServerCodec interface { ReadRequestHeader(*Request) error ReadRequestBody(interface{}) error // WriteResponse must be safe for concurrent use by multiple goroutines. WriteResponse(*Response, interface{}) error Close() error}

ServerCodec实现了为RPC会话提供读RPC请求和写PRC回复的服务端的方法。服务端调用 ReadRequestHeader和ReadRequestBody来读取连接上的请求,然后调用WriteResponse来 写回复。服务端当结束连接的时候调用Close。ReadRequestBody可能会调用一个nil参数来强迫 读取请求内容并忽略。

19. type ​​ServerError​​

type ServerError string

ServerError 代表从远程RPC连接另一端返回的错误

(1). func (ServerError) ​​Error​​

func (e ServerError) Error() string

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Docker 私有仓库
下一篇:007/Docker(一)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~