服务端通过register()方法将需要被远程调用的方法注册到map中。

func (server *Server) register(rcvr interface{}, name string, useName bool) error {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)}if !isExported(sname) && !useName {s := "rpc.Register: type " + sname + " is not exported"log.Print(s)return errors.New(s)}s.name = sname// Install the methodss.method = suitableMethods(s.typ, true)if len(s.method) == 0 {str := ""// To help the user, see if a pointer receiver would work.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
}

根据需要被远程调用的类,通过反射得到被注册的类的类型,如果没有定义所要被映射的名字,那么直接使用类名,这个名字首字母需要大写来作为暴露的类。

关于方法的遍历,将在suitableMethods()方法中处理。

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.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.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.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}methods[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}}return methods
}

遍历所需要被远程调用的类所暴露的方法,这里的方法必须满足含有三个参数,第二个参数,也就是调用的参数,不能是个指针,而作为返回值的第三个参数,则必须是个指针。同时在返回值上,必须有一个返回值,并且是异常类型的返回值。

完成上述方法的对于被调用方法 的格式检查,将得到的用来映射的名字与得到的service进行作为键值对存放在map中,表明已经完成对于被调用的方法的注册。

在接收到相应的http请求的时候,rpc包中的server同样作为http的handler,实现了ServerHttp()方法来处理远程调用的相应。

对于所要调用的类的选择,在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 = truedot := 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
}

这里,通过解析得到request中包含的所要调用的相应类的方法,由于类和方法之间通过’.’相互分割,通过’.’前后的数据得到被调用的类与方法。

通过类名在map中取得相应的service,并根据方法名从service取得相应的方法。

在得到了所调用的类以及方法之后,在那么就可以调用被远程调用的方法。在异步或者同步的情况下,通过反射机制,使用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.returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv})// The return value for the method is an error.errInter := returnValues[0].Interface()errmsg := ""if errInter != nil {errmsg = errInter.(error).Error()}server.sendResponse(sending, req, replyv.Interface(), codec, errmsg)server.freeRequest(req)
}

这里反射机制的执行的前提在于之前方法定义注册的时候对于返回值和参数个数以及类型 的严格检查。并在调用之后,将返回结果的参数作为成员在返回response的时候一并加入,在方法结束的时候,如果存在wg锁则解锁,表明一次连接的完成。

golang自带的rpc 服务端相关推荐

  1. java客户端带证书访问服务端_客户端与服务器SSL双向认证(客户端:java-服务端:java)...

    客户端与服务器SSL双向认证(java-java):含源码 (一)实现技术: JSSE(Java Security Socket Extension) 是Sun为了解决在Internet上的实现安全信 ...

  2. 阿里资深技术专家带你聊一聊——服务端的接口测试...

    服务器的接口测试通常从功能开始,如请求参数和响应参数的验证,业务逻辑或业务规则的验证,数据库操作的验证.功能正常后,将根据需要进行安全相关的检查.性能测试和一系列扩展测试,如与版本历史的兼容性测试.接 ...

  3. 微服务开源框架TARS的RPC源码解析 之 初识TARS C++服务端

    作者:Cony 导语:微服务开源框架TARS的RPC调用包含客户端与服务端,<微服务开源框架TARS的RPC源码解析>系列文章将从初识客户端.客户端的同步及异步调用.初识服务端.服务端的工 ...

  4. 深入理解 RPC : 基于 Python 自建分布式高并发 RPC 服务

    RPC(Remote Procedure Call)服务,也即远程过程调用,在互联网企业技术架构中占据了举足轻重的地位,尤其在当下微服务化逐步成为大中型分布式系统架构的主流背景下,RPC 更扮演了重要 ...

  5. NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成...

    原文:NET Core微服务之路:自己动手实现Rpc服务框架,基于DotEasy.Rpc服务框架的介绍和集成 本篇内容属于非实用性(拿来即用)介绍,如对框架设计没兴趣的朋友,请略过. 快一个月没有写博 ...

  6. java批量生成订单号_【笔记6-支付及订单模块】从0开始 独立完成企业级Java电商网站开发(服务端)...

    支付模块 实际开发工作中经常会遇见如下场景,一个支付模块,一个订单模块,有一定依赖,一个同事负责支付模块,另一个同事负责订单模块,但是开发支付模块的时候要依赖订单模块的相关类 ,方法,或者工具类,这些 ...

  7. Hadoop-rpc调用案例,服务端,客户端代码案例

    1. Hadoop-rpc框架 在hadoop中提供了一个rpc框架,通过这个rpc框架可以编写一个rpc服务端程序,然后发布出去供客户端调用. 1.1.服务端代码 其中服务端(example-had ...

  8. 【.NET Core项目实战-统一认证平台】第十六章 网关篇-Ocelot集成RPC服务

    一.什么是RPC RPC是"远程调用(Remote Procedure Call)"的一个名称的缩写,并不是任何规范化的协议,也不是大众都认知的协议标准,我们更多时候使用时都是创建 ...

  9. 基于 Python 自建分布式高并发 RPC 服务

    RPC(Remote Procedure Call)服务,也即远程过程调用,在互联网企业技术架构中占据了举足轻重的地位,尤其在当下微服务化逐步成为大中型分布式系统架构的主流背景下,RPC 更扮演了重要 ...

最新文章

  1. angular项目如何分层
  2. muduo学习笔记 - 第4章 C++多线程系统编程精要
  3. C# 读写ACCESS的OLE对象,演示图片与长文件的读写
  4. Java实现Huffman哈夫曼树
  5. vue中Ajax(axios)及Ajax(vue-resource)的使用方法
  6. leetcode841. 钥匙和房间(bfs)
  7. (简单) POJ 3984 迷宫问题,BFS。
  8. 检测同心圆_(二)光线如何被眼睛检测到?
  9. dynamo方程怎么写_【简明自控】为什么特征方程如此重要
  10. 协同进化遗传算法 代码_遗传算法在组卷中的应用
  11. mysql like n_MySQL LIKE 子句
  12. 免费python网络课程-python网络课程
  13. 学python对excel有用吗_程序员必修课:为什么非要用Python做数据分析?Excel不好吗?...
  14. springboot将模板生成pdf文件
  15. 坐飞机时为什么不能说一路顺风
  16. 纯H5+CSS3实现下雨特效
  17. OAuth2.0 - 自定义模式授权 - 短信验证码登录
  18. 如何将控制台程序发布为服务
  19. 聊聊广域网ppp协议和认证
  20. Kalevitch and Chess(翻译 day 4)

热门文章

  1. Android学习之Activity源码的理解(一)
  2. SpringBoot+Vue 完整的外卖系统,手机端和后台管理
  3. python实现图片找不同游戏_用Python实现谷歌的小恐龙游戏
  4. easyplayerpro 使用说明_EasyPlayerPro(Windows)流媒体播放器开发之ffmpeg log输出报错
  5. python ide是什么意思_初学Python使用什么IDE会更好?
  6. 怎么用nuget程序包管理器安装jquery_Nuget服务器
  7. XStream的使用
  8. Backblaze发布2016年2季度硬盘可靠性报告
  9. 手动爬虫之京东笔记本栏(ptyhon3)
  10. C#开发微信门户及应用(27)-公众号模板消息管理