【Go入门】 Go如何使得Web工作

news/2024/11/24 22:27:32/

【Go入门】 Go如何使得Web工作

前面小节介绍了如何通过Go搭建一个Web服务,我们可以看到简单应用一个net/http包就方便的搭建起来了。那么Go在底层到底是怎么做的呢?万变不离其宗,Go的Web服务工作也离不开我们第一小节介绍的Web工作方式。

web工作方式的几个概念

以下均是服务器端的几个概念

Request:用户请求的信息,用来解析用户的请求信息,包括post、get、cookie、url等信息

Response:服务器需要反馈给客户端的信息

Conn:用户的每次请求链接

Handler:处理请求和生成返回信息的处理逻辑

分析http包运行机制

下图是Go实现Web服务的工作模式的流程图

在这里插入图片描述

图3.9 http包执行流程

  1. 创建Listen Socket, 监听指定的端口, 等待客户端请求到来。

  2. Listen Socket接受客户端的请求, 得到Client Socket, 接下来通过Client Socket与客户端通信。

  3. 处理客户端的请求, 首先从Client Socket读取HTTP请求的协议头, 如果是POST方法, 还可能要读取客户端提交的数据, 然后交给相应的handler处理请求, handler处理完毕准备好客户端需要的数据, 通过Client Socket写给客户端。

这整个的过程里面我们只要了解清楚下面三个问题,也就知道Go是如何让Web运行起来了

  • 如何监听端口?
  • 如何接收客户端请求?
  • 如何分配handler?

前面小节的代码里面我们可以看到,Go是通过一个函数ListenAndServe来处理这些事情的,其实现源码如下:

func ListenAndServe(addr string, handler Handler) error {server := &Server{Addr: addr, Handler: handler}return server.ListenAndServe()
}

ListenAndServe会初始化一个sever对象,然后调用了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)
}

ListenAndServe调用了net.Listen("tcp", addr),也就是底层用TCP协议搭建了一个服务,最后调用src.Serve监控我们设置的端口。监控之后如何接收客户端的请求呢?

Serve的具体实现如下(为突出重点,仅展示关键代码),通过下面的分析源码我们可以看到客户端请求的具体处理过程:


func (srv *Server) Serve(l net.Listener) error {...ctx := context.WithValue(baseCtx, ServerContextKey, srv)for {rw, err := l.Accept()...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)}
}

这个函数里面起了一个for{},首先通过Listener接收请求:l.Accept(),其次创建一个Conn:c := srv.newConn(rw),最后单独开了一个goroutine,把这个请求的数据当做参数扔给这个conn去服务:go c.serve(connCtx)。这个就是高并发体现了,用户的每一次请求都是在一个新的goroutine去服务,相互不影响。

那么如何具体分配到相应的函数来处理请求呢?我们继续分析conn的serve方法,其源码如下(为突出重点,仅展示关键代码):

func (c *conn) serve(ctx context.Context) {...ctx, cancelCtx := context.WithCancel(ctx)c.cancelCtx = cancelCtxdefer cancelCtx()c.r = &connReader{conn: c}c.bufr = newBufioReader(c.r)c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)for {w, err := c.readRequest(ctx)...// HTTP cannot have multiple simultaneous active requests.[*]// Until the server replies to this request, it can't read another,// so we might as well run the handler in this goroutine.// [*] Not strictly true: HTTP pipelining. We could let them all process// in parallel even if their responses need to be serialized.// But we're not going to implement HTTP pipelining because it// was never deployed in the wild and the answer is HTTP/2.serverHandler{c.server}.ServeHTTP(w, w.req)w.cancelCtx()...}
}

conn首先会解析request:w, err := c.readRequest(ctx), 然后获取相应的handler去处理请求:serverHandler{c.server}.ServeHTTP(w, w.req)ServeHTTP的具体实现如下:

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {handler := sh.srv.Handlerif handler == nil {handler = DefaultServeMux}if req.RequestURI == "*" && req.Method == "OPTIONS" {handler = globalOptionsHandler{}}handler.ServeHTTP(rw, req)
}

sh.srv.Handler就是我们刚才在调用函数ListenAndServe时候的第二个参数,我们前面例子传递的是nil,也就是为空,那么默认获取handler = DefaultServeMux,那么这个变量用来做什么的呢?对,这个变量就是一个路由器,它用来匹配url跳转到其相应的handle函数,那么这个我们有设置过吗?有,我们调用的代码里面第一句不是调用了http.HandleFunc("/", sayhelloName)嘛。这个作用就是注册了请求/的路由规则,当请求uri为"/",路由就会转到函数sayhelloName,DefaultServeMux会调用ServeHTTP方法,这个方法内部其实就是调用sayhelloName本身,最后通过写入response的信息反馈到客户端。

详细的整个流程如下图所示:

在这里插入图片描述

图3.10 一个http连接处理流程

至此我们的三个问题已经全部得到了解答,你现在对于Go如何让Web跑起来的是否已经基本了解了呢?


http://www.ppmy.cn/news/1227961.html

相关文章

【Go入门】 Go搭建一个Web服务器

【Go入门】 Go搭建一个Web服务器 前面小节已经介绍了Web是基于http协议的一个服务&#xff0c;Go语言里面提供了一个完善的net/http包&#xff0c;通过http包可以很方便的搭建起来一个可以运行的Web服务。同时使用这个包能很简单地对Web的路由&#xff0c;静态文件&#xff0c…

Linux命令(125)之scp

linux命令之scp 1.scp介绍 linux命令scp用于在两个主机之间安全的复制文件和目录 2.scp用法 scp [参数] <source> <target> scp常用参数 参数说明-P指定远程主机的端口-p复制文件时&#xff0c;保留原始文件的属性(E [rootrhel77 ~]# scp 192.168.10.249.txt r…

Windows安装Vmware 虚拟机

目录 一、Vmware 虚拟机介绍 二、Vmware 虚拟机的三种网络模式 2.1桥接模式 2.2仅主机模式 2.3NAT 网络地址转换模式 三、Vmware 虚拟机的安装 一、Vmware 虚拟机介绍 VMware Workstation Pro 是一款可以在个人电脑的操作系统上创建一个完全与主机操作系统隔离的 虚拟机&…

【数据结构&C++】二叉平衡搜索树-AVL树(25)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.AVL树的概念二.AVL树节点的定义(代码…

WPF xaml Command用法介绍

WPF (Windows Presentation Foundation) 中的命令设计模式是一种用于分离用户界面逻辑和业务逻辑的方法。在WPF中&#xff0c;这种模式通过命令接口&#xff08;如 ICommand&#xff09;实现&#xff0c;使得用户界面组件&#xff08;如按钮、菜单项等&#xff09;可以触发不直…

关于DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC的一些发现

任务在哪 这个是11g以后的自动收集统计信息的后台任务&#xff0c;10g之前是在dba_scheduler_jobs里查看 SQL> SELECT CLIENT_NAME ,STATUS ,MEAN_INCOMING_TASKS_7_DAYS,MEAN_INCOMING_TASKS_30_DAYS FROM DBA_AUTOTASK_CLIENT WHERE…

SVM之SVR参数详解以及调参

SVM之SVR参数详解以及调参 一、参数、属性及方法1、参数kernel = ‘rbf’degree=3gamma=‘scale’coef0=0.0tol=0.001C=1.0epsilon=0.1shrinking=Truecache_size=200verbose=Falsemax_iter=-12、属性class_weight_coef_dual_coef_fit_status_interce

【C++历练之路】list的重要接口||底层逻辑的三个封装以及模拟实现

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; 在C的世界中&#xff0c;有一种数据结构&#xff0c;它不仅像一个神奇的瑰宝匣&#xff0c;还像一位能够在数据的海洋中航行的智慧舵手。这就是C中的list&#xff0c;一个引人入胜的工具…