摘要:校验方法在处理请求时,会遍历注册的处理函数执行。函数的实现也很简单,就是循环进行,每收到请求便创建一个协程进行处理。
作者:谭淼
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) } }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/37036.html
摘要:作者施洪宝一基础通过锁或者原子操作解决协程之间的竞争问题本文主要介绍锁通过通道有缓冲和无缓冲解决协程之间的通信问题一个协程可能同时与多个其他协程通信此时可以通过进行处理锁即是一般的互斥锁只有一个协程可以获取锁其他协程获取时会被阻塞为读写锁某 作者:施洪宝 一. go 基础 go通过锁或者原子操作解决协程之间的竞争问题, 本文主要介绍锁 go通过通道(有缓冲和无缓冲)解决协程之间的通信...
摘要:在处等待将请求放入的字段中,并且将请求放入中。在处加很明显并没有真正处理请求肯定会有从中读取请求并且处理完成后在处减,这样当请求执行完成后就可以返回给客户端端响应了。下边我们看看处理字段中数据的协程是如何启动并处理数据的。 张仕华 proxy启动 cmd/proxy/main.go文件 解析配置文件之后重点是proxy.New(config)函数 该函数中,首先会创建一个Proxy结构...
摘要:什么是一个分布式解决方案,多个节点构成的集群上层应用可以像使用单机的一样使用,底层会处理请求的转发,不停机的数据迁移等工作实例的计算能力汇集到一起,从而完成关于大数据和高并发量的的读写操作组成部分,处理客户端请求,支持协议,因此客户端访问 什么是Codis 一个分布式 Redis 解决方案,多个 Redis 节点构成的集群 上层应用可以像使用单机的 Redis 一样使用,Codis ...
摘要:代码如下正在执行时再次发送会如何处理直接返回返回信息通知正在执行如果此时在执行则会在中在结束之后执行代码如下时如果还在执行写入由于机制此时会给子进程拷贝一份数据导致双倍内存。 顺风车运营研发团队 张仕华1.redis主流程伪代码: def main(): init_server() while server_is_not_shutdown(): time = a...
摘要:集合特点无序无重复集合间操作常用命令命令含义时间复杂度将一个或多个元素加入到集合当中,已经存在于集合的元素将被忽略,是被添加的元素的数量。给定集合之间的交集将结果保存到新的集合,为给定集合当中基数最小的集合,为给定集合的个数。 Set(集合) 特点 无序 无重复 集合间操作 常用命令 命令 含义 时间复杂度 sadd 将一个或多个 member 元素加入到集合 key 当...
阅读 2047·2021-11-25 09:43
阅读 2962·2021-11-19 09:40
阅读 1024·2021-11-15 11:37
阅读 3272·2021-09-26 09:46
阅读 2574·2021-09-13 10:23
阅读 3336·2021-09-07 10:24
阅读 2277·2019-08-29 13:20
阅读 2808·2019-08-28 17:57