上一篇文章我们讲了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,请注明来意。