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. Vue.js有赞商城(思路以及总结整理)

    以下是本次项目的代码链接和预览链接:    代码链接:https://github.com/Leonardo-zyh/Vue-youzanStore    预览链接:https://leonardo- ...

  2. Sql语句模糊查询字符串的两种写法

    Sql语句模糊查询有两种写法,一种是在jdbcTemplate的查询方法参数里拼接字符串%,一种是在Sql语句里拼接%字符串. public class IsNameDaoImpl implement ...

  3. 每日一个linux命令2

    cd命令 Linux cd命令可以说是Linux中最基本的命令语句,其他的命令语句要进行操作,都是建立在使用cd命令的基础之上. 1. 命令格式 cd [目录名] 2.命令功能 切换当前目录至dirN ...

  4. 2021升级版微服务教程4—Nacos 服务注册和发现

    2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 默认文件1610014380163 教程全目录「含视 ...

  5. 【JavaWeb】jQuery 基础

    jQuery 基础 介绍 顾名思义,它是 JavaScript 和 查询,是辅助 JavaScript 开发的类库. 它的核心思想是 write less, do more. 所以它实现了很多浏览器的 ...

  6. Java类的加载过程-重点!!

    java类的加载过程有以下几步共同完成: 加载->连接->初始化.连接又分为验证.准备.解析 一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以 ...

  7. 区间合并 C++

    #include <iostream> #include <vector> #include <algorithm> using namespace std; ty ...

  8. Win 10 Docker安装和简单使用

    Win 10 Docker安装和简单使用 1.环境准备 Docker for Windows需要运行在64位Windows 10 Pro专业版.企业版或教育版(1607年纪念更新,版本14393或更高 ...

  9. alter column和modify column

    5.6中,发现其实alter column 和更改modify column 步骤是一样的 mysql> create table xs(name varchar(12),age int def ...

  10. MongoDB 总结

    目录 1. 逻辑结构 2. 安装部署 2.1 系统准备 2.2 mongodb安装 2.2.1 创建所需用户和组 2.2.2 创建mongodb所需目录结构 2.2.3 上传并解压软件到指定位置 2. ...