乐趣区

【每日笔记】【Go学习笔记】2019-01-04 Codis笔记

作者:谭淼
1、dlv 的使用
dlv 是调试 go 语言的工具,与 gdb 类似。下面是一些 dlv 的常用命令:

(1)dlv attach pid:类似与 gdb attach pid,可以对正在运行的进程直接进行调试 (pid 为进程号)。
(2)dlv debug:运行 dlv debug test.go 会先编译 go 源文件,同时执行 attach 命令进入调试模式,该命令会在当前目录下生成一个名为 debug 的可执行二进制文件,退出调试模式会自动被删除。
(3)dlv exec executable_file:直接从二进制文件启动调试模式。

调试命令(常用的为 break,continue,next,print):

注意:dlv 可以通过 goroutines 查看所有的协程,并通过“goroutine 协程号”来切换协程。
2、martini 框架
github 地址:https://github.com/go-martini…
Martini 是一个为了编写模块化 Web 应用而生的强大的 GO 语言框架。其使用参考:https://github.com/go-martini…
3、codis-fe 的启动
codis-fe 启动首先要解析参数,然后启动 martini。
m := martini.New()
m.Use(martini.Recovery())
m.Use(render.Renderer())
m.Use(martini.Static(assets, martini.StaticOptions{SkipLogging: true}))
首先调用 martini.New() 方法创建一个 Martini 结构体,然后在调用该结构体的 Use 方法注册中间件。
中间件的注册比较简单,就是向 handlers 切片添加方法。
func (m *Martini) Use(handler Handler) {
// 校验方法
validateHandler(handler)

m.handlers = append(m.handlers, handler)
}
在处理请求时,会遍历注册的处理函数执行。
func (c *context) run() {
for c.index <= len(c.handlers) {
_, err := c.Invoke(c.handler())
if err != nil {
panic(err)
}
c.index += 1

if c.Written() {
return
}
}
}
除此之外,还有一个疑问,对于静态资源,是在哪里决定 Content-Type 的呢?
func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, sizeFunc func() (int64, error), content io.ReadSeeker) {
……
// If Content-Type isn’t set, use the file’s extension to find it, but
// if the Content-Type is unset explicitly, do not sniff the type.
ctypes, haveType := w.Header()[“Content-Type”]
var ctype string
if !haveType {
ctype = mime.TypeByExtension(filepath.Ext(name))
if ctype == “” {
// read a chunk to decide between utf-8 text and binary
var buf [sniffLen]byte
n, _ := io.ReadFull(content, buf[:])
ctype = DetectContentType(buf[:n])
_, err := content.Seek(0, io.SeekStart) // rewind to output whole file
if err != nil {
Error(w, “seeker can’t seek”, StatusInternalServerError)
return
}
}
w.Header().Set(“Content-Type”, ctype)
} else if len(ctypes) > 0 {
ctype = ctypes[0]
}
……
}
从代码可以看出,是根据后缀名来决定的。
后面将会新建一个路由实例,并添加路由。
r := martini.NewRouter()
r.Get(“/list”, func() (int, string) {
names := router.GetNames()
sort.Sort(sort.StringSlice(names))
return rpc.ApiResponseJson(names)
})

r.Any(“/**”, func(w http.ResponseWriter, req *http.Request) {
name := req.URL.Query().Get(“forward”)
if p := router.GetProxy(name); p != nil {
p.ServeHTTP(w, req)
} else {
w.WriteHeader(http.StatusForbidden)
}
})
注册路由后便开启服务。
hs := &http.Server{Handler: h}
if err := hs.Serve(l); err != nil {
log.PanicErrorf(err, “serve %s failed”, listen)
}
Serve 函数的实现也很简单,就是循环进行 accept,每收到请求便创建一个协程进行处理。
func (srv *Server) Serve(l net.Listener) error {
……
for {
rw, e := l.Accept()
……
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}

退出移动版