先上一段官方给的示例代码,
type Args struct {
A, B int
}
type Quotient struct {
Quo, Rem int
}
type Arith int
func (t *Arith) Multiply(args *Args, reply *int) error {
*reply = args.A * args.B
return nil
}
func (t *Arith) Divide(args *Args, quo *Quotient) error {
if args.B == 0 {
return errors.New("divide by zero")
}
quo.Quo = args.A / args.B
quo.Rem = args.A % args.B
return nil
}
func StartServer() {
// server
go func() {
arith := new(Arith)
rpc.Register(arith)
rpc.HandleHTTP()
l, e := net.Listen("tcp", ":1234")
if e != nil {
log.Fatal("listen error:", e)
}
http.Serve(l, nil)
}()
// client
out := make(chan struct{})
go func() {
serverAddress := "127.0.0.1"
client, err := rpc.DialHTTP("tcp", serverAddress+":1234")
if err != nil {
log.Fatal("dialing:", err)
}
// Synchronous call
args := &Args{7, 8}
var reply int
err = client.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
out <- struct{}{}
}()
<-out
}
其中,最令人难以理解的是下面这段代码:
rpc.Register(arith)
rpc.HandleHTTP()
l, e := net.Listen("tcp", ":1234")
if e != nil {
log.Fatal("listen error:", e)
}
http.Serve(l, nil)
在分别执行了rpc.Register和rpc.HandleHTTP方法之后,为什么就可以直接使用http.Serve监听客户端的请求呢?
翻了一下代码,代码的逻辑方式大致如下:
rpc.HandleHTTP 实现
1、调用rpc.HandleHTTP,会直接使用DefaultServer操作逻辑, DefaultServer是一个初始化的rpc.Server指针。
// NewServer returns a new Server.
func NewServer() *Server {
return &Server{}
}
// DefaultServer is the default instance of *Server.
var DefaultServer = NewServer()
...
func HandleHTTP() {
DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
}
2、调用(server *Server) HandleHTTP函数,使用DefaultServeMux.Handle(pattern, handler)来处理,pattern和handler,这里的handdler就是rpc.DefaultServer
func (server *Server) HandleHTTP(rpcPath, debugPath string) {
http.Handle(rpcPath, server)
http.Handle(debugPath, debugHTTP{server})
}
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
3、紧接着,将pattern和handler封装到了ServeMux结构中,即DefaultServeMux中。
func (mux *ServeMux) Handle(pattern string, handler Handler) {
...
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
...
}
http.Serve 实现
1、调用http.Server函数,初始化服务
func Serve(l net.Listener, handler Handler) error {
srv := &Server{Handler: handler}
return srv.Serve(l)
}
2、创建一个连接conn,将当前srv包装起来,然后调用serve函数
func (srv *Server) Serve(l net.Listener) error {
...
for {
...
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}
func (srv *Server) newConn(rwc net.Conn) *conn {
c := &conn{
server: srv,
rwc: rwc,
}
...
}
3、调用(sh serverHandler) ServeHTTP方法,确定handler调用,如果handler == nil,则使用DefaultServeMux,正好合RPC初始化的配置对应上。
// serverHandler delegates to either the server's Handler or
// DefaultServeMux and also handles "OPTIONS *" requests.
type serverHandler struct {
srv *Server
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil { // 本文的handler=nil,直接使用DefaultServeMux
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
func (c *conn) serve(ctx context.Context) {
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
// But we're not going to implement HTTP pipelining because it
// was never deployed in the wild and the answer is HTTP/2.
serverHandler{c.server}.ServeHTTP(w, w.req)
}