Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the principle of Golang native rpc

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains "what is the principle of Golang native rpc". The content of the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what is the principle of Golang native rpc".

Several conditions are required to create a rpc interface

The type of the method is exportable

The method itself is exportable.

Method must have two parameters, either an output type or a built-in type

The second parameter of the method is the pointer type

The type returned by method is error

Analysis of the principle of rpc Service

Server end

Service registration

Handle network calls

Through reflection processing, the service registration stores the interface into map and invokes the registration service two methods.

Func Register (rcvr interface {}) error {} func RegisterName (rcvr interface {}, name string) error {} / / specify the name of the registration

Source code interpretation of registration method first of all, the underlying code of both Register and RegisterName calls the register method to register the service. Interpretation of server.go register method

Func (server * Server) register (rcvr interface {}, name string, useName bool) error {/ / create a service instance s: = new (service) s.typ = reflect.TypeOf (rcvr) s.rcvr = reflect.ValueOf (rcvr) sname: = reflect.Indirect (s.rcvr). Type (). Name () / / if the service name is empty Then use the default service name if useName {sname = name} if sname = "" {s: = "rpc.Register: no service name for type" + s.typ.String () log.Print (s) return errors.New (s)} / / to determine whether the method name is leaked. If the method name is not exposed, it will result in an unsuccessful call So return false if! token.IsExported (sname) & &! useName {s: = "rpc.Register: type" + sname + "is not exported" log.Print (s) return errors.New (s)} s.name = sname / / Install the methods / / call the suitableMethods function to return the API Determine whether the method meets the conditions as a rpc interface in suitableMethods, and if so, add s.method = suitableMethods (s.typ, true) if len (s.method) to services = 0 {str: = "" / / To help the user, see if a pointer receiver would work. / / if the method is bound to the address of the structure, the method will not be found using reflect.TypeOf () So also look for the method method: = suitableMethods (reflect.PtrTo (s.typ) bound to the address of the structure False) if len (method)! = 0 {str = "rpc.Register: type" + sname + "has no exported methods of suitable type (hint: pass a pointer to value of that type)"} else {str = "rpc.Register: type" + sname + "has no exported methods of suitable type"} Log.Print (str) return errors.New (str)} / / determines whether the service interface has been registered. If _, dup: = server.serviceMap.LoadOrStore (sname, s); dup {return errors.New ("rpc: service already defined:" + sname)} return nil}

Interpretation of suitableMethod method

Func suitableMethods (typ reflect.Type, reportErr bool) map [string] * methodType {/ / create a slice of a method methods: = make (map [string] * methodType) for m: = 0; m < typ.NumMethod (); masks + {method: = typ.Method (m) mtype: = method.Type mname: = method.Name / / Method must be exported. If method.PkgPath! = "" {continue} / / Method needs three ins: receiver, * args, * reply. / / if there are not three parameters passed in, an error will be reported. Why are there three? / / the structure instance is passed into the body of the golang method by default, so there are three parameters if mtype.NumIn ()! = 3 {if reportErr {log.Printf ("rpc.Register: method% Q has% d input parameters). Needs exactly three\ n ", mname, mtype.NumIn ()} continue} / / First arg need not be a pointer. ArgType: = mtype.In (1) if! isExportedOrBuiltinType (argType) {if reportErr {log.Printf ("rpc.Register: argument type of method% q is not exported:% Q\ n", mname ArgType)} continue} / / Second arg must be a pointer. / / determines whether the second parameter is a pointer, and returns false if it is not. ReplyType: = mtype.In (2) if replyType.Kind ()! = reflect.Ptr {if reportErr {log.Printf ("rpc.Register: reply type of method% q is not a pointer:% Q\ n", mname ReplyType)} continue} / / Reply type must be exported. If! isExportedOrBuiltinType (replyType) {if reportErr {log.Printf ("rpc.Register: reply type of method% q is not exported:% Q\ n", mname, replyType)} continue} / / Method needs one out. / / whether the result is a value and error if mtype.NumOut ()! = 1 {if reportErr {log.Printf ("rpc.Register: method% Q has% d output parameters" Needs exactly one\ n ", mname, mtype.NumOut ()} continue} / / The return type of the method must be error. If returnType: = mtype.Out (0) ReturnType! = typeOfError {if reportErr {log.Printf ("rpc.Register: return type of method% Q is% Q, must be error\ n", mname ReturnType)} continue} / / add the interface to service methods [mname] = & methodType {method: method, ArgType: argType, ReplyType: replyType}} return methods}

After receiving the request, the request will be parsed continuously. There are two methods readRequestHeader for parsing the request.

Func (server * Server) readRequestHeader (codec ServerCodec) (svc * service, mtype * methodType, req * Request, keepReading bool, err error) {/ / Grab the request header. / / received the request Code the request req = server.getRequest () err = codec.ReadRequestHeader (req) if err! = nil {req = nil if err = = io.EOF | | err = = io.ErrUnexpectedEOF {return} err = errors.New ("rpc: server cannot decode request:" + err. Error () return} / / We read the header successfully. If we see an error now, / / we can still recover and move on to the next request. KeepReading = true// encoded request, interval, so as long as the. By segmenting the data on the left and right sides of, dot: = strings.LastIndex (req.ServiceMethod, ".") If dot < 0 {err = errors.New ("rpc: service/method request ill-formed:" + req.ServiceMethod) return} serviceName: = req.ServiceMethod [: dot] methodName: = req.ServiceMethod [dot+1:] / / Look up the request. Svci, ok: = server.serviceMap.Load (serviceName) if! ok {err = errors.New ("rpc: can't find service" + req.ServiceMethod) return} svc = svci. (* service) / / when the registration service is obtained Registered interface mtype = svc.method [methodName] if mtype = = nil {err = errors.New ("rpc: can't find method" + req.ServiceMethod)} return}

ReadRequest method

Func (server * Server) readRequest (codec ServerCodec) (service * service, mtype * methodType, req * Request, argv, replyv reflect.Value, keepReading bool, err error) {service, mtype, req, keepReading, err = server.readRequestHeader (codec) / / call the readRequestHeader method above to decode And return the interface data if err! = nil {if! keepReading {return} / / discard body codec.ReadRequestBody (nil) return} / / Decode the argument value. ArgIsValue: = false / / if true, need to indirect before calling. / / determine whether the pass is a pointer. If so, you need to use the Elem () method to point to the structure if mtype.ArgType.Kind () = = reflect.Ptr {argv = reflect.New (mtype.ArgType.Elem ())} else {argv = reflect.New (mtype.ArgType) argIsValue = true} / / argv guaranteed to be a pointer now. If err = codec.ReadRequestBody (argv.Interface ()) Err! = nil {return} if argIsValue {argv = argv.Elem ()} replyv = reflect.New (mtype.ReplyType.Elem ()) switch mtype.ReplyType.Elem () .Kind () {case reflect.Map: replyv.Elem () .Set (reflect.MakeMap (mtype.ReplyType.Elem () Case reflect.Slice: replyv.Elem () .Set (reflect.MakeSlice (mtype.ReplyType.Elem () 0,0)} return}

Call method

Func (s * service) call (server * Server, sending * sync.Mutex, wg * sync.WaitGroup, mtype * methodType, req * Request, argv, replyv reflect.Value, codec ServerCodec) {if wg! = nil {defer wg.Done ()} mtype.Lock () mtype.numCalls++ mtype.Unlock () function: = mtype.method.Func / / Invoke the method, providing a new value for the reply. / / call the call method and convert the parameter to a valueof parameter, returnValues: = function.Call ([] reflect.Value {s.rcvr, argv, replyv}) / / The return value for the method is an error. / / read the returned error and convert it to interface {} errInter: = returnValues [0] .Interface () errmsg: = "" if errInter! = nil {/ / assert error errmsg = errInter. (error). Error ()} server.sendResponse (sending, req, replyv.Interface (), codec, errmsg) server.freeRequest (req)}

The general process of registration

Acquire the interface according to the reflection

Use the method to determine whether the interface conforms to the specification as a rpc interface (there are two parameters, the second parameter is a pointer, and a parameter error is returned)

If it does not conform to the specification, error will be returned. If it conforms to the specification, it will be stored in map for providing calls.

The general process of receiving a request

First of all, we constantly receive the data stream and decode it into data.data, so we need to use it. As a separator, data is truncated and read

Look up the read data in the registered map, and if found, return relevant service and other data

Make a call

Thank you for reading, the above is the content of "what is the principle of Golang native rpc". After the study of this article, I believe you have a deeper understanding of what the principle of Golang native rpc is, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report