http.ListenAndServe
创建WWW服务实现HTTP通信大致可分为两个阶段:注册路由、监听启动
- 服务端创建Socket监听指定端口,等待客户端请求到来。
- 监听Socket接受客户端请求并建立连接以获取客户端Socket,服务端通过客户端Socket与之通信。
- 服务端处理客户端请求并返回响应
Go标准库net/http
提供http.Server
可用以实现Web服务器
例如:使用单个处理程序创建HTTP服务
请求流程
- 客户端通过指定的URL将请求发送给服务端
- 服务端将请求指向到对应的处理器进行处理
- 处理器处理请求执行必要的动作
- 处理器将结果返回给客户端
type Handler struct{}func (Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {fmt.Fprintln(w, "hello world")
}func main() {//实例化http.Serversrv := http.Server{}//设置服务监听端口srv.Addr = ":80"//设置服务的处理程序srv.Handler = Handler{}//监听TCP连接并处理客户端请求if err := srv.ListenAndServe(); err != nil {panic(err)}
}
创建服务 http.Server
http.Server
定义了运行一个HTTP服务器所需参数,最基本的两个参数是Addr
和Handler
。
type Server struct {Addr stringHandler Handler ...
}
参数 | 类型 | 描述 |
---|---|---|
Addr | string |
用于指定服务器的TCP地址,形式为host:port 。为空则默认使用80端口,默认地址可省略。
|
Handler | http.Handler |
处理器,默认为http.DefaultServeMux 。
|
处理器 http.Handler
http.Handler
是一个接口,只提供了一个方法签名ServeHTTP()
。ServeHTTP()
方法签名会接受两个参数分别是http.ResponseWriter
接口和http.Request
指针。任何实现ServerHTTP()
接口方法的都是一个自定义的处理器。
type Handler interface {ServeHTTP(ResponseWriter, *Request)
}
使用注意
http.Handler
用于响应一个HTTP请求ServeHTTP()
接口方法用来将响应头和数据写入到http.ResponseWriter
中后结束请求,结束后不能再继续使用这个http.ResponseWriter
,也不能再从http.Request
的Body
体中读取数据,另外不能并发调用已完成的ServeHTTP()
。http.Handler
应该线读取请求体再写入http.ResponseWriter
,一旦开始向http.ResponseWriter
写数据就不能再从请求体中读取数据。http.Handler
只能用来读取http.Request
的Body
,不能修改已取得的请求,因为参数http.Request
是指针类型的。
响应 http.ResponseWriter
http.ResponseWriter
接口的作用是用来构建HTTP响应,且明确指定Handler.ServeHTTP()
方法返回后就不能再继续使用http.ResponseWriter
。
type ResponseWriter interface {Header() HeaderWrite([]byte) (int, error)WriteHeader(statusCode int)
}
http.ResponseWriter
接口提供了三个方法
接口方法 | 描述 |
---|---|
Header() | 用来构建响应头 |
Write() | 用于向网络连接中写入响应数据 |
WriteHeader() | 将给定的响应状态码和响应头一起通过网络连接发送给客户端 |
Write()
方法会返回一个http.Header
类型的对象来构建响应体,http.Header
对象会被WriteHeader()
响应出去。
type Header map[string][]string
监听服务 http.ListenAndServe
http.ListenAndServe()
用于在指定的TCP网络地址进行监听,然后调用服务端处理程序来处理传入的请求。
func ListenAndServe(addr string, handler Handler) error {server := &Server{Addr: addr, Handler: handler}return server.ListenAndServe()
}
http.ListenAndServe()
用于设置监听TCP地址并启动服务,监听启动实际上会实例化一个http.Server
对象,通过它调用ListenAndServe()
开启对客户端的监听。
func (srv *Server) ListenAndServe() error {if srv.shuttingDown() {return ErrServerClosed}addr := srv.Addrif addr == "" {addr = ":http"}ln, err := net.Listen("tcp", addr)if err != nil {return err}return srv.Serve(ln)
}
调用Server
实例的ListenAndServe()
会调用底层的net.Listen("tcp", addr)
,基于TCP协议创建监听Socket,通过传入的主机地址和端口号,在指定端口上监听客户端请求。
func Listen(network, address string) (Listener, error) {var lc ListenConfigreturn lc.Listen(context.Background(), network, address)
}
创建监听Socket成功后,会调用Server
实例的Serve(net.Listener)
用于接受并处理客户端请求。Serve(net.Listener)
内部会开启一个for
死循环,循环体内通过net.Listener
实例(即Listen Socket)的Accept
方法来接受客户端请求。当接收到请求后会根据请求会创建net.Conn
连接实例(即Client Socket)。为了处理并发请求,会单独为每个连接实例开启一个goroutine
去服务,请求的具体逻辑处理都会在serve()
方法内完成。
func (srv *Server) Serve(l net.Listener) error {if fn := testHookServerServe; fn != nil {fn(srv, l) // call hook with unwrapped listener}origListener := ll = &onceCloseListener{Listener: l}defer l.Close()if err := srv.setupHTTP2_Serve(); err != nil {return err}if !srv.trackListener(&l, true) {return ErrServerClosed}defer srv.trackListener(&l, false)baseCtx := context.Background()if srv.BaseContext != nil {baseCtx = srv.BaseContext(origListener)if baseCtx == nil {panic("BaseContext returned a nil context")}}var tempDelay time.Duration // how long to sleep on accept failurectx := context.WithValue(baseCtx, ServerContextKey, srv)for {rw, err := l.Accept()if err != nil {select {case <-srv.getDoneChan():return ErrServerCloseddefault:}if ne, ok := err.(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", err, tempDelay)time.Sleep(tempDelay)continue}return err}connCtx := ctxif cc := srv.ConnContext; cc != nil {connCtx = cc(connCtx, rw)if connCtx == nil {panic("ConnContext returned nil")}}tempDelay = 0c := srv.newConn(rw)c.setState(c.rwc, StateNew, runHooks) // before Serve can returngo c.serve(connCtx)}
}
客户端请求的处理集中在连接实例的serve()
方法内,serve()
方法主要实现将HTTP请求分配给指定的处理器函数来进行处理。
func (c *conn) serve(ctx context.Context) {// ...
}
首先从客户端Socket中读取HTTP请求的协议头,判断请求方法若是POST则需读取客户端提交的数据,然后交给对应的Handler来处理请求,Handler处理完毕后准备后客户端所需数据,再通过客户端Socket写给客户端。
连接实例通过readRequest()
方法解析请求,然后再通过serverHandler{c.server}.ServeHTTP(w, w.req)
中的ServeHTTP()
方法获取请求对应的处理器。
http.ListenAndSerTLS()
http.ListenAndSerTLS()
方法用于处理HTTPS请求
func http.ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) error
路由注册 http.ServeMux
http.ListenAndServe()
启动时若入参handler
处理器默认为nil
,则表示服务端会调用包变量http.DefaultServeMux
作为默认处理器,此时服务端编写的业务逻辑处理程序http.Handler()
或http.HandleFunc()
会默认注入http.DefaultServeMux
中。
例如:采用默认服务复用器启动服务
http.HandleFunc("/", func(rw http.ResponseWriter, rq *http.Request) {n, err := rw.Write([]byte(rq.RemoteAddr))if err != nil || n <= 0 {panic(err)}
})err := http.ListenAndServe(":3000", nil)
if err != nil {panic(err)
}
若不想采用默认的的http.DefaultServeMux
可使用http.NewServeMux()
创建自定义的http.ServeMux
。
func NewServeMux() *ServeMux
http://www.taodudu.cc/news/show-6312636.html
相关文章:
- 第 5 章 ROS 常用组件 4 —— rosbag / rqt工具箱
- 5G商用落地 “样板间”未达预期, URLLC如何带头提前进入5.5G时代?
- 阿里P9架构师简述从单机至亿级流量大型网站系统架构的演进过程
- 立创梁山派学习笔记——GPIO输出控制
- TMS570学习【2】pwm输出
- Android开发知识(二十二)LayoutInflater装载xml布局过程的源码解析
- Web网站架构演变历程
- PostgreSQL中的io多路复用--select和epoll实现
- Go netpoll I/O 多路复用构建原生网络模型之源码深度解析
- lc[栈与队列]---232.用栈实现队列
- Android开发知识(二十三)从源码角度分析ListView的滑动复用机制
- go 进阶 多路复用支持: 一. netpoller 初始化
- LC链表(算法系列)
- css书写顺序规范---规范书写很重要
- 论代码书写规范的重要性——分享一篇良好的代码书写规范,从小白开始培养..(表示太难了吧)
- java的书写规范
- SpringBoot使用RXTX连接串口教程及遇到的坑总结
- rxtx java 错误
- RXTX
- 高等数学:第三章 微分中值定理与导数的应用(8)曲率
- 高等数学笔记-乐经良老师-第四章-微分中值定理和导数的应用-第五节-曲线的曲率
- 微分,梯度及梯度下降法
- 考研数二第十讲 求导平面曲线的切线和法线以及曲率圆与曲率半径和弧微分
- 用R求矩阵的特征值和特征向量
- 求矩阵特征值和特征向量
- 矩阵特征值的求解过程
- matlab求矩阵特征值和特征向量、行列式
- matlab如何求矩阵特征值
- 泊松过程与排队论
- 什么是泊松分布?什么是泊松过程?
http.ListenAndServe相关推荐
- http.ListenAndServe()到底做了什么?
参考:https://studygolang.com/articles/25849?fr=sidebar http://blog.csdn.net/gophers 实现一个最简短的hello wo ...
- 思考一下http.ListenAndServe + echo+gorm+xorm的可行性?
什么是http.ListenAndServe? 什么是echo? 什么是gorm? 什么是xorm? 第一版: http.ListenAndServe +gorm 第二版: http.ListenAn ...
- 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析
目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...
- CentOS Docker安装配置部署Golang web helloworld
目录[阅读时间:约5分钟] 一.Docker简介 二.Docker的安装与配置[CentOS环境] 三.Docker部署Golang web helloworld 四.Docker与虚拟机的区别 五. ...
- RPC 笔记(03)— gRPC 概念、安装、编译、客户端和服务端示例
1. gRPC 概念 gRPC 是 Google 开源的一款高性能的 RPC 框架.GitHub 上介绍如下: gRPC is a modern, open source, high-performa ...
- Go 学习笔记(56)— Go 第三方库 sqlx (操作数据库)
1. 安装数据库 在 Go 标准库中是没有数据库驱动,只提供了驱动接口,有很多第三方实现了驱动,以下两种选择我们都可以进行操作,在本文中选择 sqlx . 第三方库 MySQL 驱动库: go-sql ...
- 如何编写可测试的golang代码
每次在开发之前,我都会考虑写好单元测试,但是随着开发的进行,就会发现事情没有这么简单,因为更多时候项目中间夹杂着很多的数据库操作,网络操作,文件操作等等,每次涉及到有这些操作的单元测试,都要花费很大的 ...
- linux 多目录makefile,royalchen
最近接触了一下微信公众号开发,刚好很久很久之前申请过一个公众号,看了下API文档,用go实现了一个简单的获取 access_token的功能. 下面的代码可以从微信服务器获取access_tokens ...
- golang中文文档_Golang 标准库 限流器 time/rate 设计与实现
限流器是后台服务中十分重要的组件,在实际的业务场景中使用居多,其设计在微服务.网关.和一些后台服务中会经常遇到.限流器的作用是用来限制其请求的速率,保护后台响应服务,以免服务过载导致服务不可用现象出现 ...
最新文章
- 如何用C#动态编译、执行代码
- 关于storm0.10.0版本的一个小bug
- 使用Docker堆栈部署的微服务-WildFly,Java EE和Couchbase
- 如何使用JPA Type Converter加密数据
- BOM+DOM+JavaScript读取与操作网页对象
- 风格之争:Coroutine vs Callback
- 为什么说阿里巴巴已进化成为一家世界级的科技公司?
- VB后台获得按键,并执行自己的函数(非钩子及热键)
- ffmpeg 安装bzlib_编译安装ffmpeg 要支持xvid、x264、mp3、ogg、amr、faac
- 【精品分享】决定边缘计算未来形态的五大需求
- IDEA修改背景颜色大全(护眼绿等)
- 自己动手XP集成SP3补丁
- 怎么提高企业微信加人的通过率,让企业微信加更多客户?快速加人,引流拓客有什么技巧(企微运营干货)
- 基于微信小程序的wifi模块使用
- .to(device)和.cuda()设置GPU的区别
- python爬虫(7)——获取京东商品评论信息
- python爬虫爬取网易云音乐歌曲_Python网易云音乐爬虫进阶篇
- Lua程序设计读书 随笔
- 一度智信|拼多多店铺取名大全
- html点击出现对勾,html , 对勾,警告,错误 三种情况