1、兄弟连区块链技术培训以太坊源码分析51rpc源码分析兄弟连Go语言+区块链技术培训以太坊源码分析(51)rpc源码分析# RPC包的官方文档Package rpc provides access to the exported methods of an object across a networkor other I/O connection. After creating a server instance objects can be registered,making it visible from the outside. Exported methods that follow
2、specificconventions can be called remotely. It also has support for the publish/subscribepattern.rpc包提供这样一种能力,可以通过网络或者其他I/O连接,可以访问对象被导出的方法。创建一个服务器之后,对象可以注册到服务器上,然后可以让外界访问。通过脂肪方式导出的方法可以被远程调用。 同时还支持发布/订阅模式。Methods that satisfy the following criteria are made available for remote access:-object must be
3、 exported-method must be exported-method returns 0, 1 (response or error) or 2 (response and error) values-method argument(s) must be exported or builtin types-method returned value(s) must be exported or builtin types符合以下标准的方法可用于远程访问:-对象必须导出-方法必须导出-方法返回0,1(响应或错误)或2(响应和错误)值-方法参数必须导出或是内置类型-方法返回值必须导出或
4、是内置类型An example method:func (s *CalcService) Add(a, b int) (int, error)When the returned error isnt nil the returned integer is ignored and the error issend back to the client. Otherwise the returned integer is send back to the client.当返回的error不等于nil的时候,返回的整形值被忽略,error被发送回客户端。 否则整形的会返回被发送回客户端。Option
5、al arguments are supported by accepting pointer values as arguments. E.g.if we want to do the addition in an optional finite field we can accept a modargument as pointer value.通过提供指针类型的参数可以使得方法支持可选参数。后面有点看不懂了。 func (s *CalService) Add(a, b int, mod *int) (int, error)This RPC method can be called wit
6、h 2 integers and a null value as third argument.In that case the mod argument will be nil. Or it can be called with 3 integers,in that case mod will be pointing to the given third argument. Since the optionalargument is the last argument the RPC package will also accept 2 integers asarguments. It wi
7、ll pass the mod argument as nil to the RPC method.RPC方法可以通过传两个integer和一个null值作为第三个参数来调用。在这种情况下mod参数会被设置为nil。或者可以传递三个integer,这样mod会被设置为指向第三个参数。尽管可选的参数是最后的参数,RPC包任然接收传递两个integer,这样mod参数会被设置为nil。The server offers the ServeCodec method which accepts a ServerCodec instance. It willread requests from the
8、codec, process the request and sends the response back to theclient using the codec. The server can execute requests concurrently. Responsescan be sent back to the client out of order.server提供了ServerCodec方法,这个方法接收ServerCodec实例作为参数。 服务器会使用codec读取请求,处理请求,然后通过codec发送回应给客户端。server可以并发的执行请求。response的顺序可能
9、和request的顺序不一致。/An example server which uses the JSON codec: type CalculatorService struct func (s *CalculatorService) Add(a, b int) int return a + b func (s *CalculatorService Div(a, b int) (int, error) if b = 0 return 0, errors.New(divide by zero)return a/b, nil calculator := new(CalculatorService
10、) server := NewServer() server.RegisterName(calculator, calculator) l, _ := net.ListenUnix(unix, &net.UnixAddrNet: unix, Name: /tmp/calculator.sock) for c, _ := l.AcceptUnix()codec := v2.NewJSONCodec(c)go server.ServeCodec(codec) The package also supports the publish subscribe pattern through the us
11、e of subscriptions.A method that is considered eligible for notifications must satisfy the following criteria:-object must be exported-method must be exported-first method argument type must be context.Context-method argument(s) must be exported or builtin types-method must return the tuple Subscrip
12、tion, error该软件包还通过使用订阅来支持发布订阅模式。被认为符合通知条件的方法必须满足以下条件:-对象必须导出-方法必须导出-第一个方法参数类型必须是context.Context-方法参数必须导出或内置类型-方法必须返回元组订阅,错误An example method: func (s *BlockChainService) NewBlocks(ctx context.Context) (Subscription, error) . Subscriptions are deleted when:-the user sends an unsubscribe request-the c
13、onnection which was used to create the subscription is closed. This can be initiatedby the client and server. The server will close the connection on an write error or whenthe queue of buffered notifications gets too big.订阅在下面几种情况下会被删除-用户发送了一个取消订阅的请求-创建订阅的连接被关闭。这种情况可能由客户端或者服务器触发。 服务器在写入出错或者是通知队列长度太大
14、的时候会选择关闭连接。# RPC包的大致结构网络协议 channels和Json格式的请求和回应的编码和解码都是同时与服务端和客户端打交道的类。网络协议channels主要提供连接和数据传输的功能。 json格式的编码和解码主要提供请求和回应的序列化和反序列化功能(Json - Go的对象)。!image(picture/rpc_1.png)# 源码解析# server.goserver.go主要实现了RPC服务端的核心逻辑。 包括RPC方法的注册, 读取请求,处理请求,发送回应等逻辑。server的核心数据结构是Server结构体。 services字段是一个map,记录了所有注册的方法和类
15、。 run参数是用来控制Server的运行和停止的。 codecs是一个set。 用来存储所有的编码解码器,其实就是所有的连接。 codecsMu是用来保护多线程访问codecs的锁。services字段的value类型是service类型。 service代表了一个注册到Server的实例,是一个对象和方法的组合。 service字段的name代表了service的namespace, typ实例的类型, callbacks是实例的回调方法, subscriptions是实例的订阅方法。type serviceRegistry mapstring*service / collection o
16、f servicestype callbacks mapstring*callback / collection of RPC callbackstype subscriptions mapstring*callbacktype Server struct services serviceRegistryrun int32codecsMu sync.Mutexcodecs *set.Set/ callback is a method callback which was registered in the servertype callback struct rcvr reflect.Valu
17、e / receiver of methodmethod reflect.Method / callbackargTypes reflect.Type / input argument typeshasCtx bool / methods first argument is a context (not included in argTypes)errPos int / err return idx, of -1 when method cannot return errorisSubscribe bool / indication if the callback is a subscript
18、ion/ service represents a registered objecttype service struct name string / name for servicetyp reflect.Type / receiver typecallbacks callbacks / registered handlerssubscriptions subscriptions / available subscriptions/notificationsServer的创建,Server创建的时候通过调用server.RegisterName把自己的实例注册上来,提供一些RPC服务的元信
19、息。const MetadataApi = rpc/ NewServer will create a new server instance with no registered handlers.func NewServer() *Server server := &Serverservices: make(serviceRegistry),codecs: set.New(),run: 1,/ register a default service which will provide meta information about the RPC service such as the ser
20、vices and/ methods it offers.rpcService := &RPCServiceserverserver.RegisterName(MetadataApi, rpcService)return server服务注册server.RegisterName,RegisterName方法会通过传入的参数来创建一个service对象,如过传入的rcvr实例没有找到任何合适的方法,那么会返回错误。 如果没有错误,就把创建的service实例加入serviceRegistry。/ RegisterName will create a service for the given
21、rcvr type under the given name. When no methods on the given rcvr/ match the criteria to be either a RPC method or a subscription an error is returned. Otherwise a new service is/ created and added to the service collection this server instance serves.func (s *Server) RegisterName(name string, rcvr
22、interface) error if s.services = nil s.services = make(serviceRegistry)svc := new(service)svc.typ = reflect.TypeOf(rcvr)rcvrVal := reflect.ValueOf(rcvr)if name = return fmt.Errorf(no service name for type %s, svc.typ.String()/如果实例的类名不是导出的(类名的首字母大写),就返回错误。if !isExported(reflect.Indirect(rcvrVal).Type
23、().Name() return fmt.Errorf(%s is not exported, reflect.Indirect(rcvrVal).Type().Name()/通过反射信息找到合适的callbacks 和subscriptions方法methods, subscriptions := suitableCallbacks(rcvrVal, svc.typ)/如果这个名字当前已经被注册过了,那么如果有同名的方法就用新的替代,否者直接插入。/ already a previous service register under given sname, merge methods/su
24、bscriptionsif regsvc, present := s.servicesname; present if len(methods) = 0 & len(subscriptions) = 0 return fmt.Errorf(Service %T doesnt have any suitable methods/subscriptions to expose, rcvr)for _, m := range methods regsvc.callbacksformatName(m.method.Name) = mfor _, s := range subscriptions reg
25、svc.subscriptionsformatName(s.method.Name) = sreturn nilsvc.name = namesvc.callbacks, svc.subscriptions = methods, subscriptionsif len(svc.callbacks) = 0 & len(svc.subscriptions) = 0 return fmt.Errorf(Service %T doesnt have any suitable methods/subscriptions to expose, rcvr)s.servicessvc.name = svcr
26、eturn nil通过反射信息找出合适的方法,suitableCallbacks,这个方法在utils.go里面。 这个方法会遍历这个类型的所有方法,找到适配RPC callback或者subscription callback类型标准的方法并返回。关于RPC的标准,请参考文档开头的RPC标准。/ suitableCallbacks iterates over the methods of the given type. It will determine if a method satisfies the criteria/ for a RPC callback or a subscript
27、ion callback and adds it to the collection of callbacks or subscriptions. See server/ documentation for a summary of these criteria.func suitableCallbacks(rcvr reflect.Value, typ reflect.Type) (callbacks, subscriptions) callbacks := make(callbacks)subscriptions := make(subscriptions)METHODS:for m := 0; m typ.NumMethod(); m+ method := typ.Method(m)mtype := method.Typemname := formatName(method.Name)if method.PkgPath != / method must be exportedcontinuevar h callbackh.isSubscribe = isPubSub(mtype)h.rcvr = rcvrh.method = methodh.errPos = -1fir
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1