Go源代码分析——http.ListenAndServe()是怎样工作的
Go对webserver的编写提供了很好的支持,标准库中提供了net/http包来方便编写server。很多教程和书籍在讲到用Go编写webserver时都会直接教新手用http包写一个最简单的hello worldserver,样例几乎相同都会像这样:
// 这就是用Go实现的一个最简短的hello worldserver.
package main import "net/http" func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`hello world`))
})
http.ListenAndServe(":3000", nil) // <-今天讲的就是这个ListenAndServe是怎样工作的
}
能够看到。代码真的很简短,仅仅须要几行。我们今天要分析的是http.ListenAndServe(),看看这里面究竟都做了些什么。
首先,http.ListenAndServe用到的全部依赖都在Go源代码中的/src/pkg/net/http/server.go文件里,打开它会发现这页代码很长,有2000+行,我们Ctrl+F直接找我们感兴趣的部分。发如今1770行左右的部分找到了http.ListenAndServe的定义:
func ListenAndServe(addr string, handler Handler) error {
// 创建一个Server结构体,调用该结构体的ListenAndServer方法然后返回
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
从这个函数中就能够看出,调用http.ListenAndServe之后真正起作用的是Server结构体LisntenAndServe方法。给http.ListenAndServe传递的參数仅仅是用来创建一个Server结构体实例,Server结构体的定义例如以下:
type Server struct {
Addr string // server的IP地址和port信息
Handler Handler // 请求处理函数的路由复用器
ReadTimeout time.Duration
WriteTimeout time.Duration
MaxHeaderBytes int
TLSConfig *tls.Config
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
ConnState func(net.Conn, ConnState)
ErrorLog *log.Logger
disableKeepAlives int32
}
假设我们不传详细的參数给http.ListenAndServe,那么它会自己主动以":http"(等价于":80")和DefaulServeMux作为參数来创建Server结构体实例。
接下来继续看看Server.ListenAndServe里面都做了些什么,1675行左右能够找到定义:
func (srv *Server) ListenAndServe() error {
addr := srv.Addr
if addr == "" {
addr = ":http" // 假设不指定server地址信息。默认以":http"作为地址信息
}
ln, err := net.Listen("tcp", addr) // 这里创建了一个TCP Listener,之后用于接收client的连接请求
if err != nil {
return err
}
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) // 调用Server.Serve()函数并返回
}
能够看到。Server.ListenAndServe中创建了一个serverListener。然后在返回时把它传给了Server.Serve()方法并调用Server.Serve()。
继续分析Server.Serve,定义的位置在1690行左右:
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
var tempDelay time.Duration
// 这个循环就是server的主循环了,通过传进来的listener接收来自client的请求并建立连接,
// 然后为每个连接创建routine运行c.serve()。这个c.serve就是详细的服务处理了
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
}
srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c, err := srv.newConn(rw)
if err != nil {
continue
}
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve() // <-这里为每个建立的连接创建routine之后进行服务
}
}
我们能够接着看看这个conn.serve()里面是怎么进行服务的。代码在1090行附近,仅仅看当中的主要部分:
func (c *conn) serve() {
origConn := c.rwc // copy it before it's set nil on Close or Hijack // 这里做了一些延迟释放和TLS相关的处理... // 前面的部分都能够忽略,这里才是基本的循环
for {
w, err := c.readRequest() // 读取client的请求
// ...
serverHandler{c.server}.ServeHTTP(w, w.req) //这里对请求进行处理
if c.hijacked() {
return
}
w.finishRequest()
if w.closeAfterReply {
if w.requestBodyLimitHit {
c.closeWriteAndWait()
}
break
}
c.setState(c.rwc, StateIdle)
}
}
经过一路的分析,http.ListenAndServe工作的流程就几乎相同明晰了,我们能够总结成一张流程图:
Go源代码分析——http.ListenAndServe()是怎样工作的的更多相关文章
- hostapd源代码分析(二):hostapd的工作机制
[转]hostapd源代码分析(二):hostapd的工作机制 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004433 在我的上一 ...
- openVswitch(OVS)源代码分析之工作流程(数据包处理)
上篇分析到数据包的收发,这篇开始着手分析数据包的处理问题.在openVswitch中数据包的处理是其核心技术,该技术分为三部分来实现:第一.根据skb数据包提取相关信息封装成key值:第二.根据提取到 ...
- openVswitch(OVS)源代码分析之工作流程(flow流表查询)
原文链接: openVswitch(OVS)源代码分析之工作流程(flow流表查询)
- kube-proxy源代码分析
摘要:假设你对kube-proxy的工作原理有一定的了解.本文基于kubernetes v1.5代码对kube-proxy的源代码文件夹结构进行了分析,并以iptables mode为例进行了完整流程 ...
- Twitter Storm源代码分析之ZooKeeper中的目录结构
徐明明博客:Twitter Storm源代码分析之ZooKeeper中的目录结构 我们知道Twitter Storm的所有的状态信息都是保存在Zookeeper里面,nimbus通过在zookeepe ...
- 转:SDL2源代码分析
1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...
- 转:RTMPDump源代码分析
0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...
- 转:ffdshow 源代码分析
ffdshow神奇的功能:视频播放时显示运动矢量和QP FFDShow可以称得上是全能的解码.编码器.最初FFDShow只是mpeg视频解码器,不过现在他能做到的远不止于此.它能够解码的视频格式已经远 ...
- hostapd源代码分析(一):网络接口和BSS的初始化
[转]hostapd源代码分析(一):网络接口和BSS的初始化 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004349 最近在做一 ...
随机推荐
- css中url的路径含义及使用
http://www.jb51.net/css/37554.html 在CSS中有用url语法来指定background-image或是其他引用文件中,如: 复制代码 代码如下: .mainheade ...
- Unable to resolve superclass of
因为用了和Google map相关的类,而Google map是单独的library,需要导入之后才能使用,因此在manifest.xml文件中的<application></app ...
- PHP 自学之路-----XML编程(Dom技术)
上一节,讲了Xml文件基本语法及元素,实体及Dtd约束技术,下面就正式进入PHP的Xml编程 使用PHP技术对Xml文件进行操作 常用的有以下三种技术: 1.PHP dom 2.PHP结合XPath操 ...
- Linux内核中网络数据包的接收-第一部分 概念和框架
与网络数据包的发送不同,网络收包是异步的的.由于你不确定谁会在什么时候突然发一个网络包给你.因此这个网络收包逻辑事实上包括两件事:1.数据包到来后的通知2.收到通知并从数据包中获取数据这两件事发生在协 ...
- netsh学习
show allowedprogram –显示被允许的程序配置 show config - 显示防火墙的配置 show currentprofile -显示 Windows 防火墙的当前配置文件. s ...
- rxvt-unicode配置
我的urxvt配置文件如下 前缀可改为rxvt然后可以使用rxvt命令启动 -/.Xresources ! urxvt color set URxvt.multichar_encoding:utf-8 ...
- Python之L.reverse()和L.sort()
# -*- coding: utf-8 -*- #python 27 #xiaodeng #Python之L.reverse()和L.sort() #http://python.jobbole.com ...
- 数据库选型之亿级数据量并发访问(MySQL集群)
刘 勇 Email:lyssym@sina.com 简介 针对实际应用中并发访问MySQL的场景,本文采用多线程对MySQL进行并发读取访问,其中以返回用户所需的数据并显示在终端为测试结束节点,即将 ...
- 微信小程序基于swiper组件的tab切换
代码地址如下:http://www.demodashi.com/demo/14010.html 一.前期准备工作 软件环境:微信开发者工具 官方下载地址:https://mp.weixin.qq.co ...
- poj 1156 Palindrome
Palindrome Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 51631 Accepted: 17768 Desc ...