go server
图片模仿build web application with golang,学习画图技巧。
通过学习发现go写http server主要有以下两种方式,本文是分析beego中的httpServer和graceServer的基础前提。通过分析源码,和unix中开发server中的方式(socket,bind,listen,accetp)串连起来,而不仅仅是go给我们提供好的几个api。
方式1:ServeHTTP方式
package main
import (
"log"
"net/http"
)
type sayHandler struct {
}
func (h *sayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
}
func main() {
log.Fatal(http.ListenAndServe(":8080", new(sayHandler)))
}
code-1-1
方式2:handleFunc方式
// Package main provides ...
package main
import (
"log"
"net/http"
)
func say(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
func main() {
http.HandleFunc("/hello", say)
log.Fatal(http.ListenAndServe(":8080", nil))
}
code-1-2
源码解析
先分析code-1-1中的代码,从ListenAndServe开始
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
code-1-3
看下Server
type Server struct {
Addr string
Handler Handler
...
}
code-1-4
继续看下Handler
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
code-1-5
这里我们看到ListenAndServe第二个参数只要实现code-1-5中的接口就可以了。
我们回到code-1-3中继续分析。
func (srv *Server) ListenAndServe() error {
....
ln, err := net.Listen("tcp", addr)
....
return srv.Serve(ln)
}
code-1-6
这里调用了Listen,继续下
func (srv *Server) Serve(l net.Listener) error {
....
for {
rw, e := l.Accept()
...
c := srv.newConn(rw)
c.setState(c.rwc, StateNew)
go c.serve(ctx)
}
}
code-1-7
这里调用了Accetp,得到了socket连接。
看一下newConn,这个主要是封装下,可以读取server的方法。go c.serve(ctx)
可以每个连接一个协程处理。
func (srv *Server) newConn(rwc net.Conn) *conn {
c := &conn{
server: srv,
rwc: rwc,
}
...
return c
}
code-1-8
// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
...
for {
w, err := c.readRequest(ctx)
...
serverHandler{c.server}.ServeHTTP(w, w.req)
...
}
code-1-9
serverHandler{c.server}.ServeHTTP(w, w.req)
会调用ServeHTTP方法。如果调用时传了Handler,则调用Handler的Serve。到现在我们回答了code-1-1中的问题了。
type serverHandler struct {
srv *Server
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}
code-1-10
code-1-2中的代码使用的是DefaultServeMux,我们下篇文章分析。
参考链接
http-servers
function handler
build-web-application-with-golang