func (srv *Server) Serve(l net.Listener) error {defer l.Close()
var tempDelay time.Duration // how long to sleep on accept failure
for {
rw, e := l.Accept()
if e != nil {
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
if srv.ReadTimeout != 0 {
rw.SetReadDeadline(time.Now().Add(srv.ReadTimeout))
}
if srv.WriteTimeout != 0 {
rw.SetWriteDeadline(time.Now().Add(srv.WriteTimeout))
}
c, err := srv.newConn(rw)
if err != nil {
continue
}
go c.serve()
}
panic("not reached")
}
监控之后如何接收客户端的请求呢?上面代码执行监控端口之后,调用了srv.Serve(net.Listener)函数,这个函数就是处理接收客户端的请求信息。这个函数里面起了一个 for{},首先通过 Listener 接收请求,其次创建一个 Conn,最后单独开了一个goroutine,把这个请求的数据当做参数扔给这个 conn 去服务:go c.serve()。这个就是高并发体现了,用户的每次请求都是在一个新的 goroutine 去服务,相互不影响。那么如何具体分配到相应的函数来处理请求呢?
 
conn 首先会解析 request:c.readRequest(),然后获取相应的 handler:handler := c.server.Handler,也就是我们刚才在调用函数ListenAndServe 时候的第二个参数,我们前面例子传递的是 nil,也就是为空,那么默认获取 handler = DefaultServeMux,那么这个变量用来做什么的呢?对,这个变量就是一个路由器,它用来匹配 url 跳转到其相应的 handle 函数,那么这个我们有设置过吗?有,我们调用的代码里面第一句不是调用了 http.HandleFunc("/", sayhelloName)嘛。
 
这个作用就是注册了请求/的路由规则,当请求 uri 为"/",路由就会转到函数 sayhelloName,DefaultServeMux会调用 ServeHTTP 方法,这个方法内部其实就是调用 sayhelloName 本身,最后通过写入response 的信息反馈到客户端。
 
Go 的 http 有两个核心功能:Conn、ServeMux
type Handler interface {
    ServeHTTP(ResponseWriter, *Request) // 路由实现器
}
Handler 是一个接口,但是前一小节中的 sayhelloName 函数并没有实现 ServeHTTP 这个接口,为什么能添加呢?原来在 http 包里面还定义了一个类型 HandlerFunc,我们定义的函 数 sayhelloName 就是这个 HandlerFunc 调用之后的结果,这个类型默认就实现了ServeHTTP 这个接口,即我们调用了 HandlerFunc(f),强制类型转换 f 成为 HandlerFunc 类型,这样 f 就拥有了 ServHTTP 方法。
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}
 
按顺序做了几件事:
1 调用了 DefaultServerMux 的 HandleFunc
2 调用了 DefaultServerMux 的 Handle3 往 DefaultServeMux 的 map[string]muxEntry 中增加对应的 handler 和路由规则
• 其次调用 http.ListenAndServe(":9090", nil)
按顺序做了几件事情:
1 实例化 Server
2 调用 Server 的 ListenAndServe()
3 调用 net.Listen("tcp", addr)监听端口
4 启动一个 for 循环,在循环体中 Accept 请求
5 对每个请求实例化一个 Conn,并且开启一个 goroutine 为这个请求进行服务 go c.serve()
6 读取每个请求的内容 w, err := c.readRequest()
7 判断 handler 是否为空,如果没有设置 handler(这个例子就没有设置
handler),handler 就设置为 DefaultServeMux
8 调用 handler 的 ServeHttp
9 在这个例子中,下面就进入到 DefaultServerMux.ServeHttp
10 根据 request 选择 handler,并且进入到这个 handler 的 ServeHTTP
mux.handler(r).ServeHTTP(w, r)
11 选择 handler:
A 判断是否有路由能满足这个 request(循环遍历 ServerMux 的 muxEntry)
B 如果有路由满足,调用这个路由 handler 的 ServeHttp
C 如果没有路由满足,调用 NotFoundHandler 的 ServeHttp

Go 的 http 包的源码,通过代码我们可以看到整个的 http 处理过程的更多相关文章

  1. 各个版本spring的jar包以及源码下载地址

    各个版本spring的jar包以及源码下载地址,目前最高版本到spring4.1.2,留存备用: http://maven.springframework.org/release/org/spring ...

  2. 怎样加入� android private libraries 中的包的源码

    先上图: 这里以加入� afinal_0.5.1_bin.jar 为例. 第一步:加入�jar包到libs里面,系统自己主动把jar载入到android private libraries中: 第二步 ...

  3. httpd的rpm包及源码安装配置

    httpd的rpm包及源码安装配置 1.rpm包安装 系统环境: [root@zhaochj ~]# cat /etc/issue CentOS release 6.4 (Final) Kernel ...

  4. Eclipse里面的Maven项目如果下载依赖的jar包的源码

    Window---------Properties---------------Maven--------------勾选Download Artifact Sources和Download Arti ...

  5. eclipse调试第三方jar包需要源码的问题

    很多时候测试自己的jar包功能时,需要有一个测试工程导入该jar包,但是一般在调试的时候,需要跟进去看看步骤和逻辑是否正确,这个时候就需要在jar包的源码中下断点.最近刚好自己也会经常这样做,也遇到了 ...

  6. yum更换国内源、yum下载rpm包、源码包安装 使用介绍

    第5周第4次课(4月19日) 课程内容: 7.6 yum更换国内源7.7 yum下载rpm包7.8/7.9 源码包安装 7.6 yum更换国内源 当yum仓库的软件不好用时,例如很多yum源都是国外的 ...

  7. 安装包RPM包或源码包

    RPM工具 # mount /dev/cdrom /mnt     挂载光盘 # rpm     软件包管理器 -i     安装(需要安装包完整名称) -v    可视化 -h    显示安装进度 ...

  8. RPM包或源码包

    安装RPM包或源码包 点击vmware右下角光驱连接. 安装rpm包 -i:表示安装 -v:表示可视化 -h:表示显示安装进度 (同时使用) --force:表示强制安装,即使覆盖属于其他包的文件也要 ...

  9. 安装RPM包或者源码包

    RPM工具 RPM他是以一种数据库记录的方式将我们所需要的套件安装到linux主机的一套管理程序关于RPM各个选项的含义如下-i:表示安装-v:表示可视化-h:表示安装进度在安装RPM包时,常用的附带 ...

  10. IDEA 全局搜索 Jar 包中源码内容

    引言 项目开发过程中,经常遇到需要在依赖的 Jar 包查看源码,查找类方法和属性,介绍两种在 IDEA 中搜索 Jar 包内容的方式 方式一:双击 SHIFT 快捷键 输入需要查询的类名或方法名 方式 ...

随机推荐

  1. [LC] 82. Remove Duplicates from Sorted List II

    Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numb ...

  2. [LC] 226. Invert Binary Tree

    Invert a binary tree. Example: Input: 4 / \ 2 7 / \ / \ 1 3 6 9 Output: 4 / \ 7 2 / \ / \ 9 6 3 1 /* ...

  3. 推送至远程仓库使用git push -u的原因

    第一次把本地仓库推送至远端时,为了以后方便一定要使用 git push -u origin master [此处是把本地的master分支推送至远程的master分支]

  4. 杂谈php之什么是cgi,fastcgi,fpm,cli,mod

    杂谈PHP极少关注的问题 本话题来自于我使用PHP进行网页爬虫的一次经历.对于一个web开发者来说,PHP解释器本身却知之甚小,实在是惭愧呐! 首先这个话题要从几个提问开始. PHP是什么? 外文名: ...

  5. Vue错误信息解决

    在运行Vue项目时提示如下错误: [Vue warn]: You are using the runtime-only build of Vue where the template compiler ...

  6. 吴裕雄--天生自然KITTEN编程:演唱会

  7. myecplise上将工程部署到应用下时,经常出现 An internal error occurred during: "Add Deployment". java.lang.NullPointEx

    myecplise上将工程部署到应用下时,经常出现 An internal error occurred during: "Add Deployment". java.lang.N ...

  8. [PyTorch入门]之数据导入与处理

    数据导入与处理 来自这里. 在解决任何机器学习问题时,都需要在处理数据上花费大量的努力.PyTorch提供了很多工具来简化数据加载,希望使代码更具可读性.在本教程中,我们将学习如何从繁琐的数据中加载. ...

  9. 阿里大数据竞赛season1 总结

    关于样本测试集和训练集数量上,一般是选择训练集数量不小于测试集,也就是说训练集选取6k可能还不够,大家可以多尝试得到更好的效果: 2. 有人提出归一化方面可能有问题,大家可以查查其他的归一化方法,但是 ...

  10. 再谈拍照,OPPO这次拿什么和iPhone7拼?

    ​一年一度的iPhone新机如期而至,双摄像头成为iPhone 7 Plus标配,尽管在这之前,双摄像头已有少数厂商在手机上装备,但苹果一出,市场必定全面跟进.无论各大厂商是否采用双摄像头,在手机拍照 ...