1. Github 地址 https://github.com/valyala/fasthttp

  2. fastHttp 服务端的处理请求的过程

    1. 工作过程

    2. 主要代码

      1. 设置监听地址 server.go

        func (s *Server) ListenAndServe(addr string) error {
        ln, err := net.Listen("tcp4", addr)
        if err != nil {
        return err
        }
        if tcpln, ok := ln.(*net.TCPListener); ok {
        return s.Serve(tcpKeepaliveListener{
        TCPListener: tcpln,
        keepalive: s.TCPKeepalive,
        keepalivePeriod: s.TCPKeepalivePeriod,
        })
        }
        return s.Serve(ln)
        }
      2. 初始化协程池并启动,当接收到请求后,调 wp.Serve 交给协程池去处理请求 server.go

      func (s *Server) Serve(ln net.Listener) error {
      
      	.....
      
      	wp := &workerPool{
      WorkerFunc: s.serveConn,
      MaxWorkersCount: maxWorkersCount,
      LogAllErrors: s.LogAllErrors,
      Logger: s.logger(),
      connState: s.setState,
      }
      wp.Start() for {
      if c, err = acceptConn(s, ln, &lastPerIPErrorTime); err != nil {
      wp.Stop()
      return err
      }
      s.setState(c, StateNew)
      atomic.AddInt32(&s.open, 1)
      if !wp.Serve(c) {
      atomic.AddInt32(&s.open, -1)
      s.writeFastError(c, StatusServiceUnavailable,
      "The connection cannot be served because Server.Concurrency limit exceeded")
      c.Close()
      s.setState(c, StateClosed)
      }
      }
      ......
      }
      1. 获取请求的句柄 server.go

        func acceptConn(s *Server, ln net.Listener, lastPerIPErrorTime *time.Time) (net.Conn, error) {
        for {
        c, err := ln.Accept()
        ......
        return c, nil
        }
        }
      2. 协程池处理请求 workerPool.go

        // 从协程池中获取某个协程对应的 句柄channel,然后将 3 中获取到的 请求句柄推入channel
        func (wp *workerPool) Serve(c net.Conn) bool {
        ch := wp.getCh()
        if ch == nil {
        return false
        }
        ch.ch <- c
        return true
        } // 这个是协程池工作最重要的部分,获取协程池中协程对应的channel
        func (wp *workerPool) getCh() *workerChan {
        var ch *workerChan
        createWorker := false wp.lock.Lock()
        ready := wp.ready
        n := len(ready) - 1
        // 获取协程句柄channel失败,如果可以新建协程的话就进行新建,如果不可用新建的话,返回的句柄channel为nil,本次请求被拒绝服务
        if n < 0 {
        if wp.workersCount < wp.MaxWorkersCount {
        createWorker = true
        wp.workersCount++
        }
        } else {
        // 获取协程句柄channel 成功
        ch = ready[n]
        ready[n] = nil
        wp.ready = ready[:n]
        }
        wp.lock.Unlock() if ch == nil {
        if !createWorker {
        return nil
        }
        // 新建协程句柄,且为之创建协程
        vch := wp.workerChanPool.Get()
        ch = vch.(*workerChan)
        go func() {
        wp.workerFunc(ch)
        wp.workerChanPool.Put(vch)
        }()
        }
        return ch
        } func (wp *workerPool) workerFunc(ch *workerChan) {
        var c net.Conn
        var err error
        for c = range ch.ch {
        //协程的句柄channel 出现nil的时候 当前协程就退出了
        if c == nil {
        break
        } // wp.WorkerFunc是在初始化协程池的时候注册的方法,是 s.serveConn
        if err = wp.WorkerFunc(c); err != nil && err != errHijacked {
        ......
        }
        }
        ......
        if !wp.release(ch) {
        break
        }
        }
        .....
        // 协程的句柄channel 出现nil的时候 当前协程就退出了,退出后将work协程数自减
        wp.workersCount--
        ......
        } // 请求处理完之后 将当前协程的句柄channel 放入协程池的ready切片中,待下次获取协程的句柄channel的时候进行复用(复用这个句柄channel就相当于复用了对应的协程)
        func (wp *workerPool) release(ch *workerChan) bool {
        ch.lastUseTime = time.Now()
        wp.lock.Lock()
        if wp.mustStop {
        wp.lock.Unlock()
        return false
        }
        wp.ready = append(wp.ready, ch)
        wp.lock.Unlock()
        return true
        }
      3. 实际处理请求的方法 server.go

        func (s *Server) serveConn(c net.Conn) (err error) {
        .....
        //上下文对象复用并初始化上下文
        ctx := s.acquireCtx(c)
        ......
        //执行在初始化server的时候自定义的 逻辑
        if continueReadingRequest {
        s.Handler(ctx)
        }
        .....
        // 处理http响应
        }
  3. 高效的原因

    1. fastHttp 协程池 详情见 2.2.2 、2.2.4
    2. fastHttp 对象复用
      1. 协程channle对象 复用 详见2.2.4 的 getCh() 函数
      2. 上下文对象复用 详见2.2.5

注:

本文为自己对fastHttp的理解,如有疑问,欢迎一起讨论交流

如需转载请注明出处:https://www.cnblogs.com/zhuchenglin/p/14358612.html

fastHttp服务端处理请求的过程的更多相关文章

  1. Query通过Ajax向PHP服务端发送请求并返回JSON数据

    Query通过Ajax向PHP服务端发送请求并返回JSON数据 服务端PHP读取MYSQL数据,并转换成JSON数据,传递给前端Javascript,并操作JSON数据.本文将通过实例演示了jQuer ...

  2. jQuery通过Ajax向PHP服务端发送请求并返回JSON数据

    SON(JavaScript Object Notation) 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解析和生成.JSON在前后台交互的过程中发挥着相当出色的作用.请接着往下看教 ...

  3. Request对象 --web浏览器向web服务端的请求

    一]Request对象常用方法        1)StringBuffer getRequestURL()            url表示访问web应用的完整路径            2)Stri ...

  4. 服务端CURL请求

    服务端与服务端之间,也存在接口编程. 比如我们网站服务端,需要发送短信.发送邮件.查询快递等,都需要调用第三方平台的接口. 1.php中发送请求 ①file_get_contents函数 :传递完整的 ...

  5. 基于jFinal建立简单的服务端-接收请求并返回指定内容

    本菜鸡是一名弱弱的测试工程师,最近完成了一个支付相关的项目,项目工作中,需要建立一个模拟支付宝的网关,主要是接收请求并返回数据.作为一名没有丝毫开发经验的菜鸡,初期入门相当费劲,主要还是思维上的转变. ...

  6. Visual Studio 2015 Bowser Link的功能不停的向服务端发送请求

    Visual Studio 2015新建的mvc项目 默认在每个视图上生成一些JavaScript脚本

  7. 在java服务端判断请求是来自哪个终端

    在servlet中,我们可以获取到HttpServletRequest,然后通过HttpServletRequest的getHeader("User-Agent")方法获取请求头中 ...

  8. ajax对服务端发送请求

    //兼容处理获取ajax对象 var req = ''; if (window.XMLHttpRequest)    req = new XMLHttpRequest(); else    req = ...

  9. nextjs 服务端渲染请求参数

    Post.getInitialProps = async function (context) { const { id } = context.query const res = await fet ...

随机推荐

  1. VRay for SketchUp渲染图黑原因及解决方案

    很多人都遇到用Vray for SketchUp云渲染的时候,渲染出来的图片是全黑或者是局部是黑色, 这是什么原因呢? 1.有一种情况是,SketchUp的文件储存机制和其他的软件有些不同,它是把模型 ...

  2. 借助Docker搭建JMeter+Grafana+Influxdb监控平台

    我们都知道Jmeter提供了原生的结果查看,既然有原生的查看结果,为什么还要多此一举使用其他工具进行查看呢,除了查看内容丰富外还有最主要的原因:Jmeter提供的查看结果插件本身是比较消耗性能的,所以 ...

  3. 【Redis3.0.x】NoSql 入门

    Redis3.0.x NoSql 入门 概述 NoSQL(Not Only SQL ),即不仅仅是 SQL,泛指非关系型的数据库.NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑 ...

  4. 【SpringMVC】SpringMVC 拦截器

    SpringMVC 拦截器 文章源码 拦截器的作用 SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理. 谈到拦截器,还有另外一个概 ...

  5. LeetCode 371两数之和

    题目描述: 不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a .b ​​​​​​​之和. 思路: 既然不能使用运算符操作就要考虑到,位运算的加法. 加法有进位的时候和不进位的时候 ...

  6. MySQL select 查询之分组和过滤

    SELECT 语法 SELECT [ALL | DISTINCT] {* | table.* | [table.field1[as alias1][,table.field2[as alias2]][ ...

  7. 【EXP/IMP】问题总结

    为了使测试与生产数据保持一致,只需要导出数据的时候,可以将测试库的表truncate,保留其它如索引,trigger,constraints,grants等不用再重新导. exp时候rows=y,其它 ...

  8. os-hackos-3-docker提权

    0x00 cewl http://192.168.43.179/websec/爬取页面所有的单词做成字典 hydra -l contact@hacknos.com -P cewl.txt 192.16 ...

  9. Centos6.9安装ACFS

    安装完oracle 11GR2的RAC后,使用asmca打开图形化界面后,发现Volumes和ASM Cluster File System两个选项卡不能用 原因是因为ACFS不支持CentOS 解决 ...

  10. [Usaco2002 Feb]Rebuilding Roads重建道路

    题目描述 一场可怕的地震后,奶牛用N个牲口棚(1 <= N <= 150,编号1..N)重建了农民John的牧场.奶牛没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是唯一 ...