建议看这篇文章前先看一下net/http文档 http://golang.org/pkg/net/http/

net.http包里面有很多文件,都是和http协议相关的,比如设置cookie,header等。其中最重要的一个文件就是server.go了,这里我们阅读的就是这个文件。

几个重要概念

ResponseWriter: 生成Response的接口

Handler: 处理请求和生成返回的接口

ServeMux: 路由,后面会说到ServeMux也是一种Handler

Conn : 网络连接

具体分析

几个接口:

Handler

实现了handler接口的对象就意味着往server端添加了处理请求的逻辑。

  1. type Handler interface {
  2.  
  3. ServeHTTP(ResponseWriter, *Request) // 具体的逻辑函数
  4.  
  5. }

  下面是三个接口(ResponseWriter, Flusher, Hijacker):

ResponseWriter, Flusher, Hijacker

  1. // ResponseWriter的作用是被Handler调用来组装返回的Response的
  2. type ResponseWriter interface {
  3. // 这个方法返回Response返回的Header供读写
  4. Header() Header
  5.  
  6. // 这个方法写Response的Body
  7. Write([]byte) (int, error)
  8.  
  9. // 这个方法根据HTTP State Code来写Response的Header
  10. WriteHeader(int)
  11. }
  12.  
  13. // Flusher的作用是被Handler调用来将写缓存中的数据推给客户端
  14. type Flusher interface {
  15. // 这个方法将写缓存中数据推送给客户端
  16. Flush()
  17. }
  18.  
  19. // Hijacker的作用是被Handler调用来关闭连接的
  20. type Hijacker interface {
  21. // 这个方法让调用者主动管理连接
  22. Hijack() (net.Conn, *bufio.ReadWriter, error)
  23.  
  24. }

  

response

实现这三个接口的结构是response(这个结构是http包私有的,在文档中并没有显示,需要去看源码)

  1. // response包含了所有server端的http返回信息
  2. type response struct {
  3. conn *conn // 保存此次HTTP连接的信息
  4. req *Request // 对应请求信息
  5. chunking bool // 是否使用chunk
  6. wroteHeader bool // header是否已经执行过写操作
  7. wroteContinue bool // 100 Continue response was written
  8. header Header // 返回的http的Header
  9. written int64 // Body的字节数
  10. contentLength int64 // Content长度
  11. status int // HTTP状态
  12. needSniff bool // 是否需要使用sniff。(当没有设置Content-Type的时候,开启sniff能根据HTTP body来确定Content-Type)
  13.  
  14. closeAfterReply bool //是否保持长链接。如果客户端发送的请求中connection有keep-alive,这个字段就设置为false。
  15.  
  16. requestBodyLimitHit bool //是否requestBody太大了(当requestBody太大的时候,response是会返回411状态的,并把连接关闭)
  17.  
  18. }

  在response中是可以看到

  1. func (w *response) Header() Header
  2. func (w *response) WriteHeader(code int)
  3. func (w *response) Write(data []byte) (n int, err error)
  4. func (w *response) Flush()
  5. func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error)

  

这么几个方法。所以说response实现了ResponseWriter,Flusher,Hijacker这三个接口

HandlerFunc

handlerFunc是经常使用到的一个type

  1. type HandlerFunc func(ResponseWriter, *Request)
  2.  
  3. // ServeHTTP calls f(w, r).
  4. func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
  5. f(w, r)
  6. }

 

这里需要多回味一下了,这个HandlerFunc定义和ServeHTTP合起来是说明了什么?说明HandlerFunc的所有实例是实现了ServeHttp方法的。另,实现了ServeHttp方法就是什么?实现了接口Handler!

所以你以后会看到很多这样的句子:

 

  1. func AdminHandler(w ResponseWriter, r *Request) {
  2. ...
  3. }
  4. handler := HandlerFunc(AdminHandler)
  5. handler.ServeHttp(w,r)

  

请不要讶异,你明明没有写ServeHttp,怎么能调用呢? 实际上调用ServeHttp就是调用AdminHandler。

HandlerFunc(AdminHandler)是一个转换而非一个函数调用,因为http.HandlerFunc是一个类型。HandlerFunc显示了在Go语言接口机制中一些不同寻常的特点。这是一个有实现了接口http.Handler方法的函数类型。ServeHTTP方法的行为调用了它本身的函数。因此HandlerFunc是一个让函数值满足一个接口的适配器(此处是http.Handler接口适配器,因为serverHTTP实现了Handler接口),这里函数和这个接口仅有的方法有相同的函数签名。实际上,这个技巧让一个单一的类型例如MyHandler以多种方式满足http.Handler接口。

附带上一个play.google写的一个小例子

http://play.golang.org/p/nSt_wcjc2u

有兴趣继续研究的同学可以继续试验下去

下面接着看Server.go

ServerMux结构

它就是http包中的路由规则器。你可以在ServerMux中注册你的路由规则,当有请求到来的时候,根据这些路由规则来判断将请求分发到哪个处理器(Handler)。

它的结构如下:

  1. type ServeMux struct {
  2. mu sync.RWMutex //锁,由于请求设计到并发处理,因此这里需要一个锁机制
  3. m map[string]muxEntry // 路由规则,一个string对应一个mux实体,这里的string就是我注册的路由表达式
  4. }

  下面看一下muxEntry

  1. type muxEntry struct {
  2. explicit bool // 是否精确匹配
  3. h Handler // 这个路由表达式对应哪个handler
  4. }

  

看到这两个结构就应该对请求是如何路由的有思路了:

当一个请求request进来的时候,server会依次根据ServeMux.m中的string(路由表达式)来一个一个匹配,如果找到了可以匹配的muxEntry,就取出muxEntry.h,这是个handler,调用handler中的ServeHTTP(ResponseWriter, *Request)来组装Response,并返回。

ServeMux定义的方法有:

  1. func (mux *ServeMux) match(path string) Handler //根据path获取Handler
  2. func (mux *ServeMux) handler(r *Request) Handler //根据Request获取Handler,内部实现调用match
  3. func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) //!!这个说明,ServeHttp也实现了Handler接口,它实际上也是一个Handler!内部实现调用handler
  4. func (mux *ServeMux) Handle(pattern string, handler Handler) //注册handler方法
  5.  
  6. func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) //注册handler方法(直接使用func注册)

  

在godoc文档中经常见到的DefaultServeMux是http默认使用的ServeMux

var DefaultServeMux = NewServeMux()

如果我们没有自定义ServeMux,系统默认使用这个ServeMux。

换句话说,http包外层(非ServeMux)中提供的几个方法:

  1. func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
  2. func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
  3. DefaultServeMux.HandleFunc(pattern, handler)
  4. }

  

实际上就是调用ServeMux结构内部对应的方法。

Server

下面还剩下一个Server结构

  1. type Server struct {
  2. Addr string // 监听的地址和端口
  3. Handler Handler // 所有请求需要调用的Handler(实际上这里说是ServeMux更确切)如果为空则设置为DefaultServeMux
  4. ReadTimeout time.Duration // 读的最大Timeout时间
  5. WriteTimeout time.Duration // 写的最大Timeout时间
  6. MaxHeaderBytes int // 请求头的最大长度
  7. TLSConfig *tls.Config // 配置TLS
  8. }

  Server提供的方法有:

  1. func (srv *Server) Serve(l net.Listener) error //对某个端口进行监听,里面就是调用for进行accept的处理了
  2. func (srv *Server) ListenAndServe() error //开启http server服务,内部调用Serve
  3. func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error //开启https server服务,内部调用Serve

  当然Http包也直接提供了方法供外部使用,实际上内部就是实例化一个Server,然后调用ListenAndServe方法

  1. func ListenAndServe(addr string, handler Handler) error //开启Http服务
  2. func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error //开启HTTPs服务

  

参考:http://www.cnblogs.com/yjf512/archive/2012/08/22/2650873.html

Golang Http Server源码阅读的更多相关文章

  1. go 中 select 源码阅读

    深入了解下 go 中的 select 前言 1.栗子一 2.栗子二 3.栗子三 看下源码实现 1.不存在 case 2.select 中仅存在一个 case 3.select 中存在两个 case,其 ...

  2. Kubernetes 学习(九)Kubernetes 源码阅读之正式篇------核心组件之 Scheduler

    0. 前言 继续上一篇博客阅读 Kubernetes 源码,参照<k8s 源码阅读>首先学习 Kubernetes 的一些核心组件,首先是 kube-scheduler 本文严重参考原文: ...

  3. gin 源码阅读(2) - http请求是如何流入gin的?

    推荐阅读: gin 源码阅读(1) - gin 与 net/http 的关系 本篇文章是 gin 源码分析系列的第二篇,这篇文章我们主要弄清一个问题:一个请求通过 net/http 的 socket ...

  4. 【原】AFNetworking源码阅读(一)

    [原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...

  5. Android源码阅读 – Zygote

    @Dlive 本文档: 使用的Android源码版本为:Android-4.4.3_r1 kitkat (源码下载: http://source.android.com/source/index.ht ...

  6. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  7. CI框架源码阅读笔记1 - 环境准备、基本术语和框架流程

    最开始使用CI框架的时候,就打算写一个CI源码阅读的笔记系列,可惜虎头蛇尾,一直没有行动.最近项目少,总算是有了一些时间去写一些东西.于是准备将之前的一些笔记和经验记录下来,一方面权作备忘,另一方面时 ...

  8. 转-OpenJDK源码阅读导航跟编译

    OpenJDK源码阅读导航 OpenJDK源码阅读导航 博客分类: Virtual Machine HotSpot VM Java OpenJDK openjdk 这是链接帖.主体内容都在各链接中.  ...

  9. Netty源码阅读(一) ServerBootstrap启动

    Netty源码阅读(一) ServerBootstrap启动 转自我的Github Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速 ...

随机推荐

  1. CentOS如何挂载U盘(待更新)

    使用Linux系统时,经常需要用到U盘,下面介绍以下如何再CentOS上挂载U盘. 首先,切换到root用户. 首先,切换到root用户. 首先,切换到root用户. 重要的事情说三遍,很多同学都说, ...

  2. sum() 求和用法

    def func(*args): # sum = 0 # for el in args: # sum += el # return sum return sum(args) # sum() 求和 de ...

  3. FIO测试磁盘的iops

    FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, ...

  4. marquee 滚动到文字上时停止滚动,自定义停止方法

    我要实现的效果如下图:当鼠标移到续费提醒文字上时,文字滚动停止,并出现后面的关闭按钮:当鼠标移出文字时,文字继续滚动,后面的关闭按钮不显示. 在网上查到的marquee停止滚动的的代码是这样的: &l ...

  5. 关于j使用ava匿名类的好处总结

    匿名类,除了只能使用一次,其实还有其他用处,比如你想使用一个类的protected方法时,但是又和这个类不在同一个包下,这个时候匿名类就派上用场了,你可以定义一个匿名类继承这个类,在这个匿名类中定义一 ...

  6. AE中IHookHelper的用法 来自http://blog.sina.com.cn/s/blog_6faf711d0100xs1x.html

    IHookHelper 主要在用在自定义类型于AE带的的ICommand或ITool等, 1.实例化IHookHelper 对象: IHookHelper m_hookHelper = new Hoo ...

  7. linux_kernel_uaf漏洞利用实战

    前言 好像是国赛的一道题.一个 linux 的内核题目.漏洞比较简单,可以作为入门. 题目链接: 在这里 正文 题目给了3个文件 分配是 根文件系统 , 内核镜像, 启动脚本.解压运行 boot.sh ...

  8. UnicodeEncodeError: 'ascii' codec can't encode characters in position 2-5: ordin al not in range(128)——解决方案备注

    在vim中使用ycm插件时,偶尔会出现: “UnicodeEncodeError: 'ascii' codec can't encode characters in position 2-5: ord ...

  9. python中的字符串编码问题——3.各操作系统下的不同编码方式

    各操作系统下的不同编码方式  先看一下 linux,python2.7 >>> B = b'\xc3\x84\xc3\xa8' >>> B.decode('utf- ...

  10. MongoDB 安装和使用问题总结

    1. 一直安装不了[一直next下去但最后没有发现生成文件夹] 去掉 Installing MongoDB Compass 前面的打勾 2. 需要开两个cmd运行mongodb 开第一个,输入以下运行 ...