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. Protein interaction|insight QUANTA|SYBYL COMPOSER|MODELLER|SWISS_MODEL|WHAT IF|3D-JIGSAW|CPH-ModelGPCRs|Membrane protein|

    生命组学 蛋白质之间的互作可以有以下应用: Eg:改变蛋白质基因,从而组改变结构,削弱蛋白质之间的相互作用. Eg:数据模拟出蛋白质的靶点,即结合腔,将此数据存入结合化合物的dataset,用于制药 ...

  2. JavaScript的数据类型有哪些?

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. Android开发之《Module相互引用,NDK不能正常Debug》

    解决Android Studio不能进入调试模式问题 Android Studio 2.2.3 native debug 无法调试?:https://www.zhihu.com/question/54 ...

  4. 产品需求说明书 PRD模版

    XXX产品需求说明书 [版本号:V+数字]                 编  制: 日  期: 评  审:   日  期: 批  准: 日  期:       修订记录 版本 修订章节 修订内容 ...

  5. e代驾狂野裁员 O2O逐渐恢复理智?

    O2O逐渐恢复理智?" title="e代驾狂野裁员 O2O逐渐恢复理智?">     近段时间以来,O2O行业堪称"哀鸿遍野",十分凄惨.巨头 ...

  6. CSS中网格布局实战(初级)

    大家好,网格布局是我们在网页布局中经常用到的,那这里我就给大家分享一篇简单的网格布局,让大家能简单明了的了解网格布局的基本内容.闲话不多说,直接进入主题! 第一步,基本的框架结构.这里直接一个div来 ...

  7. C++走向远洋——22(项目一,三角形,类)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:sanjiaoxing.cpp * 作者:常轩 * 微信公众号: ...

  8. 初学Qt——tableview操作

    先做简短记录改天有空再详细讲一些吧 使用QSqlQueryModel绑定了TableView,因为需要用到数据表中Id这一项,但又不想显示出来,找到方法是 在绑定之后对tableView 调用setC ...

  9. Spring事务Transactional和动态代理(一)-JDK代理实现

    系列文章索引: Spring事务Transactional和动态代理(一)-JDK代理实现 Spring事务Transactional和动态代理(二)-cglib动态代理 Spring事务Transa ...

  10. js笔记系列之--时间及时间戳

    js入门系列之 时间及时间戳 时间及时间戳 时间及时间戳是js里面很常见的一个概念,在我们写前端页面的时候,经常会遇到需要获取当前时间的情况,所以,了解js中的时间概念非常重要.而时间戳是指格林威治时 ...