广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Golang原生rpc的原理是什么
  • 853
分享到

Golang原生rpc的原理是什么

2023-06-29 21:06:54 853人浏览 八月长安
摘要

这篇文章主要讲解了“golang原生rpc的原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang原生rpc的原理是什么”吧!创建rpc接口,需要几个条件方法的类型是可输出的方

这篇文章主要讲解了“golang原生rpc的原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang原生rpc的原理是什么”吧!

创建rpc接口,需要几个条件

  • 方法的类型是可输出的

  • 方法的本身也是可输出的

  • 方法必须有两个参数,必须是输出类型或者是内建类型

  • 方法的第二个参数是指针类型

  • 方法返回的类型为error

rpc服务原理分析

server端

  • 服务注册

  • 处理网络调用

服务注册 通过反射处理,将接口存入到map中,进行调用 注册服务两个方法

func ReGISter (rcvr interface{}) error {}func RegisterName (rcvr interface{} , name string) error {}//指定注册的名称

注册方法的源代码解读 首先,无论是Register还是RegisterName底层代码都是调用register方法,进行服务注册。 server.go register方法解读

func (server *Server) register(rcvr interface{}, name string, useName bool) error {//创建一个service实例s := new(service)s.typ = reflect.TypeOf(rcvr)s.rcvr = reflect.ValueOf(rcvr)sname := reflect.Indirect(s.rcvr).Type().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)}//判断方法名是否暴漏的,如果方法名不是暴露的,则会导致调用不成功,所以返回falseif !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//调用suitableMethods函数,进行返回接口,在suitableMethods中判断方法是否符合作为rpc接口的条件,如果符合,则进行添加到services中s.method = suitableMethods(s.typ, true)if len(s.method) == 0 {str := ""// To help the user, see if a pointer receiver would work.//如果方法绑定到结构体的地址上,使用reflect.TypeOf()是不会发现方法的,所以也要进行查找绑定到结构体地址上的方法method := suitableMethods(reflect.PtrTo(s.typ), 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)}//判断服务接口是否已经注册。if _, dup := server.serviceMap.LoadOrStore(sname, s); dup {return errors.New("rpc: service already defined: " + sname)}return nil}

suitableMethod方法解读

func suitableMethods(typ reflect.Type, reportErr bool) map[string]*methodType {//创建一个方法的切片methods := make(map[string]*methodType)for m := 0; m < typ.NumMethod(); m++ {method := typ.Method(m)mtype := method.Typemname := method.Name// Method must be exported.if method.PkgPath != "" {continue}// Method needs three ins: receiver, *args, *reply.//如果传入的参数,不为三个,则会报错,这里为什么是三个?//golang方法体中默认传入结构体实例,所以request,*response,结构体实例一共三个参数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.//判断第二个参数是否为指针,如果不为指针,则返回false。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.//返回结果是否为一个值,且为errorif 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}//将接口加入servicemethods[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}}return methods}

接收到请求后会不断的解析请求 解析请求的两个方法 readRequestHeader

func (server *Server) readRequestHeader(codec ServerCodec) (svc *service, mtype *methodType, req *Request, keepReading bool, err error) {// Grab the request header.//接收到请求,对请求进行编码req = server.getRequest()err = codec.ReadRequestHeader(req)if err != nil {req = nilif 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//编码后的请求,进行间隔,所以只要进行将.的左右两边的数据进行分割,就能解码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)//获取到注册服务时,注册的接口mtype = svc.method[methodName]if mtype == nil {err = errors.New("rpc: can't find method " + req.ServiceMethod)}return}

readRequest方法

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)//调用上面的readRequestHeader方法,进行解码,并返返回接口数据if err != nil {if !keepReading {return}// discard bodycodec.ReadRequestBody(nil)return}// Decode the argument value.argIsValue := false // if true, need to indirect before calling.//判断传擦是否为指针,如果为指针,需要使用Elem()方法,进行指向结构体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方法

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方法,并将参数转化为valueof型参数,returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})// The return value for the method is an error.//将返回的error进行读取,转化为interface{}型errInter := returnValues[0].Interface()errmsg := ""if errInter != nil {//将error进行断言errmsg = errInter.(error).Error()}server.sendResponse(sending, req, replyv.Interface(), codec, errmsg)server.freeRequest(req)}

注册的大概流程

  • 根据反射,进行接口的获取

  • 使用方法判断接口是否符合作为rpc接口的规范(有两个参数,第二个参数为指针,返回一个参数error)

  • 如果不符合规范,将返回error,符合规范,将存入map,进行提供调用

接收请求的大概流程

  • 首先,不断的接收数据流,并进行解码,解码之后为data.data,所以我们需要使用 . 作为分隔符,进行数据的截切和读取

  • 将读取的数据在注册的map中进行查找,如果查找到,返回相关的service和其他数据

  • 进行调用

感谢各位的阅读,以上就是“Golang原生rpc的原理是什么”的内容了,经过本文的学习后,相信大家对Golang原生rpc的原理是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

您可能感兴趣的文档:

--结束END--

本文标题: Golang原生rpc的原理是什么

本文链接: https://www.lsjlt.com/news/326443.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Golang原生rpc的原理是什么
    这篇文章主要讲解了“Golang原生rpc的原理是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang原生rpc的原理是什么”吧!创建rpc接口,需要几个条件方法的类型是可输出的方...
    99+
    2023-06-29
  • Go的内置RPC原理是什么
    这篇文章主要介绍“Go的内置RPC原理是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Go的内置RPC原理是什么”文章能帮助大家解决问题。从一个 Demo 入手为了快速进入状态,我们先搞一个 D...
    99+
    2023-07-05
  • golang channel原理是什么
    在Go语言中,channel是一种用于传递数据的数据类型。可以把它看作一个通信管道,用于goroutine之间的数据传输。 Chan...
    99+
    2023-10-20
    golang
  • RPC消息协议设计原理是什么
    这篇文章主要介绍了RPC消息协议设计原理是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇RPC消息协议设计原理是什么文章都会有所收获,下面我们一起来看看吧。消息边界RPC 需要在一条 TCP 链接上进行多次...
    99+
    2023-06-02
  • golang编译的原理是什么
    Golang的编译原理主要涉及以下几个步骤: 词法分析:将源代码分解为一个个的词法单元,比如关键字、标识符、常量、运算符等。 ...
    99+
    2023-10-25
    golang
  • golang中的gc原理是什么
    今天小编给大家分享一下golang中的gc原理是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解...
    99+
    2022-10-19
  • golang的编译原理是什么
    Golang(或Go)的编译原理是将Go源代码转换为机器码的过程。下面是Golang的编译过程的简要概述: 词法分析(Lexic...
    99+
    2023-10-22
    golang
  • golang切片原理是什么
    golang切片原理是底层数组、长度和容量、切片的扩容和切片的操作。详细介绍:1、底层数组,切片是建立在底层数组之上的,底层数组是实际存储元素的地方。切片通过指针指向底层数组的起始位置;2、长度和容量,切片的长度不能超过容量,但可以通过追加...
    99+
    2023-12-12
    golang切片
  • golang select的实现原理是什么
    在Go语言中,`select`语句用于从多个通道中接收数据,并且只有当其中一个通道可以接收数据时,`select`语句才会执行相应的...
    99+
    2023-10-27
    golang
  • golang互斥锁的原理是什么
    Golang中的互斥锁(Mutex)是一种用于保护共享资源的机制。当多个goroutine同时访问共享资源时,可能会导致数据竞争和不...
    99+
    2023-10-23
    golang
  • golang锁的实现原理是什么
    golang锁的实现原理是通过互斥锁和读写锁来保护共享资源的访问。互斥锁是一种基本的锁机制,用于保护共享资源,使用一个标志位来表示资源是否被占用,当一个goroutine获取到互斥锁后,其他goroutine就会被阻塞,直到该gorouti...
    99+
    2023-12-12
    Golang
  • golang map实现原理是什么
    Golang中的map是一种哈希表数据结构,用于存储键值对。它的实现原理是使用哈希函数将键映射到哈希表中的一个桶(bucket),每...
    99+
    2023-08-15
    golang map
  • 云原生已来,云原生是什么?
    前言Internet 改变了人们生活、工作、学习和娱乐的方式。技术发展日新月异,云计算市场风起“云”涌,从最初的物理机到虚拟机(裸金属) ,再到容器(Container),而互联网架构也从集中式架构到分布式架构 ,再到云原生架构。如今 “云...
    99+
    2023-06-05
  • golang调度模型的原理是什么
    Golang调度模型的原理是基于"Go"关键字和goroutine的概念。Golang中的goroutine是一种轻量级的线程,由G...
    99+
    2023-10-20
    golang
  • golang内存分配的原理是什么
    Golang中的内存分配是通过运行时系统来管理的。以下是Golang内存分配的原理: 堆分配:Golang使用一个堆来存储动态分...
    99+
    2023-10-21
    golang
  • Golang中编译器的原理是什么
    本篇文章给大家分享的是有关Golang中编译器的原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。首先先来认识以下go的代码源文件分类&...
    99+
    2022-10-19
  • golang协程实现的原理是什么
    Golang中的协程(goroutine)是一种轻量级的线程,由Go语言的运行时系统进行管理。协程的实现原理主要包括以下几个方面: ...
    99+
    2023-10-25
    golang
  • golang协程调度的原理是什么
    Golang的协程调度器的原理是基于M:N的模型。其中M代表操作系统的线程(Machine),N代表Golang的协程(Gorout...
    99+
    2023-10-23
    golang
  • Golang中 WaitGroup的实现原理是什么
    这篇文章给大家介绍Golang中 WaitGroup的实现原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1 前言WaitGroup是Golang应用开发过程中经常使用的并发控制技术。WaitGroup,可理解...
    99+
    2023-06-19
  • Golang中map的实现原理是什么
    这篇“Golang中map的实现原理是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Golang中map的实现原理是什么...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作