上一篇文章我们讲了net/rpc中client部分的实现,我本机源码安装路径在/usr/local/go,这net/rpc(golang 1.4版本)涉及到的相关代码主要有:

server.go

方法注册:

因为从client我们知道是复用的socket来实现并发调用rpc方法,我们先从方法注册来看源码部分:

// Server对象大都是保存方法存根,保证对象互斥的 type Server struct  mu sync.RWMutex // protects the serviceMap  serviceMap map[]*service reqLock sync@H_868_47@mutex// protects freeReq  freeReq * respLock sync// protects freeResp  freeResp Response} func NewServer()return&ServerserviceMap: make(@H_573_15@map)}// rpc.Register默认使用了一个Server,只对serviceMap进行了初始化 var DefaultServer=// rpc的service包括方法名、方法反射,类型等 type service  name // name of service  rcvr reflectValue// receiver of methods for the service  typ reflectType// type of the receiver  method map@H_115_29@methodType // registered methods // 无论是RegisterName、Register最终都调用了register的内部方法 func server )registerrcvr interface{},bool error // 保证注册服务安全,先加锁 server.@H_573_15@muLock defer serverUnlock// 如果服务为空,默认注册一个 ifserviceMap ==nil// @L_696_22@注册服务的反射信息  s :=new styp  reflectTypeOfrcvrrcvr ValueOf// 可以使用自定义名称  sname Indirects).Type().Name name  """rpc.Register: no service name for type "+typ logPrint errorsNew// 方法必须是暴露的,既服务名首字符大写 !isExportedsname&&"rpc.Register: type "" is not exported"// 不允许重复注册  _ present [];("rpc: service already defined: " snamename  sname // 开始注册rpc struct内部的方法存根 @H_573_15@method  suitableMethodstrue// 如果struct内部一个方法也没,那么直接报错,错误信息还非常详细  len@H_115_29@method 0 str // To Help the user,see if a pointer receiver would work.  method reflectPtrTo),136)">false" has no exported methods of suitable type (hint: pass a pointer to value of that typE)"else" has no exported methods of suitable type"str// 保存在server的serviceMap中 name] s // 上文提到了服务还需要方法存根的注册 func suitableMethodstyp reflect reportErr  map@H_115_29@methodType // 根据方法名创建保存内部@L_507_4@map methods @H_115_29@methodType// @L_696_22@rpc struct内部的方法 for m 0;< typNumMethod m++@H_931_363@method@H_115_29@m mtype  methodName// 之前对这行代码觉得比较奇葩,方法是否是暴露,是看是否有PkgPath的,如果是私有方法,PkgPath显示包名 PkgPathconTinue// 判断是否是三个参数:第一个是结构本身,第二个是参数,第三个是返回值 // Method needs three ins: receiver,*args,*reply.  mtypeNumIn3 reportErr Println"method""has wrong number of ins:"())// args是指针类型 // First arg need not be a pointer.  argType In(1isExportedOrBuilTinTypeargType"argument type not exported:" argType// reply是指针类型 // Second arg must be a pointer.  replyType 2 replyTypeKindPtr"reply type not a pointer:"// Reply type must be exported. // reply必须是可暴露的 replyType"reply type not exported:"// Method needs one out. // 必须有一个返回值,而且要是error NumOut1"has wrong number of outs:"// The return type of the method must be error.  returnType Out typeOfError "returns" returnType(),0)">"not error" methods&ArgTypeReplyType}

请求调用:

方法已经被注册成功,接下来我们看看是如何客户端发送请求调用的:

func Acceptlis netListener conn err  lisFatal"rpc.Serve: accept:" errError// TODO(r): exit? // accept连接以后,打开一个goroutIne处理请求  go serverServeConnconnconn ioReadWriteCloser buf  bufioNewWriter srv gobServerCodec rwc dec gobNewDecoder encNewEncoderbuf encBuf buf// 根据指定的codec进行协议解析 ServeCodecsrvcodec ServerCodec sending sync@H_868_47@mutex// 解析请求  req argv replyv keepReadingreadrequestcodec debugLog  ioEOF "rpc:"keepReading break// send a response if we actually managed to read a header. // 如果当前请求错误了,我们应该返回信息,然后继续处理  req sendResponsesending invalidrequest codecfreerequestreq// 因为需要继续处理后续请求,所以开一个goruTine处理rpc方法  go servicecallserver sending// 如果连接关闭了需要释放资源 Close readrequestHeader* keepReading  err error// 解析头部,如果失败,直接返回了 getrequestReadrequestHeader||ErrUnexpectedEOF"rpc: server cAnnot decode request: "Printf"rpc: [trace:%v]\n"Tracer// We read the header successfully. If we see an error Now,0)">// we can still recover and move on to the next request.  keepReading true// @L_696_22@请求中xxx.xxx中.的位置  dot LasTindexserviceMethod".""rpc: service/method request ill-formed: "// 拿到struct名字和方法名字  servicename [:dot methodName +:]// Look up the request.// 加读锁,@L_696_22@对象 RLockservicenameRUnlock"rpc: can't find service "// @L_696_22@反射类型,看见rpc中的发射其实是预先放入map中的 @H_573_15@methodName"rpc: can't find method " readrequest replyv reflectValuereadrequestHeader// discard body ReadrequestBody(nil// 解析请求中的args  argIsValue // if true,need to indirect before calling.  argv @H_115_29@mtypeElem// argv guaranteed to be a pointer Now. argvInterface());// 初始化reply类型  replyv s  call codec numCallsfunctionFunc// Invoke the method,providing a new value for the reply. // 这里是真正调用rpc方法的地方  returnValues functionCall([]})// The return value for the method is an error.  errInter  returnValues[]. errmsg  errInter.(error// 处理返回请求了  errmsg sendResponsesending  reply  errmsg  resp getResponse// Encode the response header  respserviceMethodError errmsg reply  invalidrequest // 上一文提到,客户端是根据序号来定位请求的,所以需要原样返回 SeqWriteResponseresp reply"rpc: wriTing response:"freeResponse 

资源重用:

上面把大致的rpc请求都说明了,server有一个技巧是重用对象,这里使用的是链表方式处理的:

// 可以看出使用一个free list链表,来避免request以及Response对象频繁创建,导致GC压力 getrequestreqLockfreeReq (freeReq .nextreq {} freerequestfreeReq server req server getResponserespLockfreeResp ResponsefreeResp resp  freeResponsefreeResp server resp server 最后,sending这把锁的目的是避免同一个套接字快速请求中避免返回包写入乱序,因此避免一个包完整写入完毕才允许下一个返回写入套接字。通过rpc包源码解析,可以看到标准库中的核心思想还是chAnnel+mutex实现复用对象,以及各种方式的复用,避免GC压力,在我们以后写高性能服务端可以借鉴的地方。

###########################

大佬总结

以上是大佬教程为你收集整理的Golang 1.4 net/rpc server源码解析全部内容,希望文章能够帮你解决Golang 1.4 net/rpc server源码解析所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。