完成第三章的书写

This commit is contained in:
astaxie
2012-09-05 16:11:37 +08:00
parent 50ae2dfd49
commit 6e11478f1a
6 changed files with 232 additions and 92 deletions

134
3.3.md
View File

@@ -1,85 +1,49 @@
#3.3 Go如何使得web工作
前面小节介绍了如何通过Go搭建一个web服务我们可以看到简单的应用了一个net/http包就方便的搭建起来了。那么他底层到底是怎么做的呢但是万变不离其宗他离不开我们第一小节介绍的web工作方式。
##对应web工作方式的几个概念
Request用户请求的信息
Response服务器需要反馈给客户端的信息
Conn用户的每次请求链接
Handler处理请求和生成返回信息的处理逻辑
##分析http包运行机制
![](images/3.3.http.png?raw=true)
(1) 创建listen socket, 在指定的监听端口, 等待客户端请求的到来
(2) listen socket接受客户端的请求, 得到client socket, 接下来通过client socket与客户端通信
(3) 处理客户端的请求, 首先从client socket读取http请求的协议头, 如果是post协议, 还可能要
读取客户端上传的数据, 然后处理请求, 准备好客户端需要的数据, 通过client socket写给客户端
##web执行的过程分析
针对前一小节里面的代码我们来一行行的分析一下大概的http包里面执行流程应该是这样
- 首先调用Http.HandleFunc
按顺序做了几件事:
1 调用了DefaultServerMux的HandleFunc
2 调用了DefaultServerMux的Handle
3 往DefaultServeMux的map[string]muxEntry中增加对应的handler和路由规则
- 其次调用http.ListenAndServe(":12345", 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这个例子就没有设置handlerhandler就设置为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
## links
* [目录](<preface.md>)
* 上一节: [GO搭建一个简单的web服务](<3.2.md>)
* 下一节: [Go的http包执行原理](<3.4.md>)
## LastModified
* $Id$
#3.3 Go如何使得Web工作
前面小节介绍了如何通过Go搭建一个Web服务我们可以看到简单的应用了一个net/http包就方便的搭建起来了。那么他底层到底是怎么做的呢但是万变不离其宗他离不开我们第一小节介绍的Web工作方式。
##对应web工作方式的几个概念
以下均是服务器端的相应概念
Request用户请求的信息用来解析用户的请求信息包括post、get、cookie、url等信息
Response服务器需要反馈给客户端的信息
Conn用户的每次请求链接
Handler处理请求和生成返回信息的处理逻辑
##分析http包运行机制
如下图所示是Go实现Web工作模式的流程图
![](images/3.3.http.png?raw=true)
(1) 创建listen socket, 在指定的端口监听, 等待客户端请求的到来
(2) listen socket接受客户端的请求, 得到client socket, 接下来通过client socket与客户端通信
(3) 处理客户端的请求, 首先从client socket读取http请求的协议头, 如果是post协议, 还可能要读取客户端上传的数据, 然后跟给相应的handler处理请求, 准备好客户端需要的数据, 通过client socket写给客户端
这整个的过程里面我们只要了解清楚下面三个问题也就知道Go是如何让Web运行起来了
- 如何监听端口?
- 如何接收客户端请求?
- 如何分配handler
前面小节的代码里面我们可以看到Go是通过一个函数来操作这个事情的`ListenAndServe`来监听起来的这个底层其实这样处理的初始化一个server对象然后调用了`net.Listen("tcp", addr)`也就是底层起的是TCP协议然后监控了我们设置的端口。
监控之后如何接收客户端的请求呢?上面的监控端口之后,就调用了`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对应请求函数的路由器那么这个我们有设置过吗?有,我们调用的代码里面第一句不是调用了`http.HandleFunc("/", sayhelloName)`嘛。这个就是注册了相应的路由url为"/"的请求到函数sayhelloNameDefaultServeMux会调用ServeHTTP方法这个方法内部其实就是调用sayhelloName本身最后通过写入response的信息反馈到客户端。
至此我们的三个问题已经全部得到了解答你现在对于Go如何让Web跑起来的是否已经大概清楚了呢
## links
* [目录](<preface.md>)
* 上一节: [GO搭建一个简单的web服务](<3.2.md>)
* 下一节: [Go的http包详解](<3.4.md>)
## LastModified
* $Id$