创建WWW服务实现HTTP通信大致可分为两个阶段:注册路由、监听启动

  1. 服务端创建Socket监听指定端口,等待客户端请求到来。
  2. 监听Socket接受客户端请求并建立连接以获取客户端Socket,服务端通过客户端Socket与之通信。
  3. 服务端处理客户端请求并返回响应

Go标准库net/http提供http.Server可用以实现Web服务器

例如:使用单个处理程序创建HTTP服务

请求流程

  1. 客户端通过指定的URL将请求发送给服务端
  2. 服务端将请求指向到对应的处理器进行处理
  3. 处理器处理请求执行必要的动作
  4. 处理器将结果返回给客户端
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服务器所需参数,最基本的两个参数是AddrHandler

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.RequestBody体中读取数据,另外不能并发调用已完成的ServeHTTP()
  • http.Handler应该线读取请求体再写入http.ResponseWriter,一旦开始向http.ResponseWriter写数据就不能再从请求体中读取数据。
  • http.Handler只能用来读取http.RequestBody,不能修改已取得的请求,因为参数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相关推荐

  1. http.ListenAndServe()到底做了什么?

    参考:https://studygolang.com/articles/25849?fr=sidebar ​ http://blog.csdn.net/gophers 实现一个最简短的hello wo ...

  2. 思考一下http.ListenAndServe + echo+gorm+xorm的可行性?

    什么是http.ListenAndServe? 什么是echo? 什么是gorm? 什么是xorm? 第一版: http.ListenAndServe +gorm 第二版: http.ListenAn ...

  3. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  4. CentOS Docker安装配置部署Golang web helloworld

    目录[阅读时间:约5分钟] 一.Docker简介 二.Docker的安装与配置[CentOS环境] 三.Docker部署Golang web helloworld 四.Docker与虚拟机的区别 五. ...

  5. RPC 笔记(03)— gRPC 概念、安装、编译、客户端和服务端示例

    1. gRPC 概念 gRPC 是 Google 开源的一款高性能的 RPC 框架.GitHub 上介绍如下: gRPC is a modern, open source, high-performa ...

  6. Go 学习笔记(56)— Go 第三方库 sqlx (操作数据库)

    1. 安装数据库 在 Go 标准库中是没有数据库驱动,只提供了驱动接口,有很多第三方实现了驱动,以下两种选择我们都可以进行操作,在本文中选择 sqlx . 第三方库 MySQL 驱动库: go-sql ...

  7. 如何编写可测试的golang代码

    每次在开发之前,我都会考虑写好单元测试,但是随着开发的进行,就会发现事情没有这么简单,因为更多时候项目中间夹杂着很多的数据库操作,网络操作,文件操作等等,每次涉及到有这些操作的单元测试,都要花费很大的 ...

  8. linux 多目录makefile,royalchen

    最近接触了一下微信公众号开发,刚好很久很久之前申请过一个公众号,看了下API文档,用go实现了一个简单的获取 access_token的功能. 下面的代码可以从微信服务器获取access_tokens ...

  9. golang中文文档_Golang 标准库 限流器 time/rate 设计与实现

    限流器是后台服务中十分重要的组件,在实际的业务场景中使用居多,其设计在微服务.网关.和一些后台服务中会经常遇到.限流器的作用是用来限制其请求的速率,保护后台响应服务,以免服务过载导致服务不可用现象出现 ...

最新文章

  1. 如何用C#动态编译、执行代码
  2. 关于storm0.10.0版本的一个小bug
  3. 使用Docker堆栈部署的微服务-WildFly,Java EE和Couchbase
  4. 如何使用JPA Type Converter加密数据
  5. BOM+DOM+JavaScript读取与操作网页对象
  6. 风格之争:Coroutine vs Callback
  7. 为什么说阿里巴巴已进化成为一家世界级的科技公司?
  8. VB后台获得按键,并执行自己的函数(非钩子及热键)
  9. ffmpeg 安装bzlib_编译安装ffmpeg 要支持xvid、x264、mp3、ogg、amr、faac
  10. 【精品分享】决定边缘计算未来形态的五大需求
  11. IDEA修改背景颜色大全(护眼绿等)
  12. 自己动手XP集成SP3补丁
  13. 怎么提高企业微信加人的通过率,让企业微信加更多客户?快速加人,引流拓客有什么技巧(企微运营干货)
  14. 基于微信小程序的wifi模块使用
  15. .to(device)和.cuda()设置GPU的区别
  16. python爬虫(7)——获取京东商品评论信息
  17. python爬虫爬取网易云音乐歌曲_Python网易云音乐爬虫进阶篇
  18. Lua程序设计读书 随笔
  19. 一度智信|拼多多店铺取名大全
  20. html点击出现对勾,html , 对勾,警告,错误 三种情况

热门文章

  1. 18年春季第一题 PAT甲级 1144 The Missing Number (20分) 上限感很重要
  2. c语言中signal函数详细说明--举例
  3. mysql绑定多个ip地址 (mysql给用户授权了, 还是无法远程连接)
  4. 甲骨文混合云战略融合数据库技术
  5. 安卓编程常见错误记录
  6. 【数据分析干货】全网最全!各行业常见的业务指标整理(四)-财务指标
  7. 记录一次对学校考试系统的漏洞挖掘
  8. FlexRay概述 -FlexRay的基本组件及状态机图
  9. 用go实现linux命令行
  10. wsl2下安装lammps