50

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

 5 years ago
source link: https://studygolang.com/articles/17488?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

作者:谭淼

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):

bVbmMS2?w=1826&h=1466

注意: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)
   }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK