首页 > 其他分享 >Go Web 基础--原理总结

Go Web 基础--原理总结

时间:2023-05-07 22:37:04浏览次数:41  
标签:Web err 请求 nil -- srv Go 服务器 客户端

Web的工作方式

  对于普通的上网过程

  浏览器本身是一个客户端,当你输入URL的时候,首先浏 览器会去请求DNS服务器,通过DNS获取相应的域名对应的IP,然后通过IP地址找到IP对应的服务器 后,要求建立TCP连接,等浏览器发送完HTTP Request(请求)包后,服务器接收到请求包之后才开 始处理请求包,服务器调用自身服务,返回HTTP Response(响应)包;客户端收到来自服务器的响 应后开始渲染这个Response包里的主体(body),等收到全部的内容随后断开与该服务器之间的TCP 连接。

  Web服务器的工作原理

  客户端通过TCP/IP协议建立到服务器的链接

  客户端向服务器发送Http请求协议包,请求服务器里的资源

  服务器向客户机发送HTTP协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调 用动态语言的解释引擎负责处理“动态内容”,并将处理得到的数据返回给客户端

  客户机与服务器断开。由客户端解释HTML文档,在客户端屏幕上渲染图形结果

  HTTP协议

  HTTP是一种让Web服务器与浏览器(客户端)通过Internet发送与接收数据的协议,它建立在TCP协议 之上。它是一个请求、响应协议—客户端发出一个请求,服务器响应这个请 求。在HTTP中,客户端总是通过建立一个连接与发送一个HTTP请求来发起一个事务。服务器不能主动 去与客户端联系,也不能给客户端发出一个回调连接。客户端与服务器端都可以提前中断一个连接

  Get与Post的区别

  Get请求消息体为空,Post请求带有消息体

  Get提交的数据会放在URL后,Post是将数据放在Http包的body中

  GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制。

  GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密 码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该 用户的账号和密码。

基于Go语言创建一个服务器

  示例代码中的关键字可以参考之前写的随笔!!!

package main

import (
    "fmt"
    "net/http"
    "strings"
)

func GetInitInfo(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    fmt.Println(r.Form)
    fmt.Println(r.URL.Path)
    fmt.Println(r.URL.Scheme)
    for k, v := range r.Form {
        fmt.Println("key:", k)
        fmt.Println("val:", strings.Join(v, ""))
    }
    fmt.Fprintf(w, "this is init information")
}

func main() {
    http.HandleFunc("/init", GetInitInfo)
    err := http.ListenAndServe("localhost:8080", nil)
    if err != nil {
        panic(err)
    }
    
}

结果:

 服务端几个必备的概念

  Request:用户请求的信息,用来解析用户请求的信息,包括Post,Get,Cookie,Url等信息

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

  Conn:用户的每次请求链接

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

分析Http包的运行机制

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

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

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

三个值得探究的问题

  1.如何监听端口?

  2.如何接收客户端请求?

  3.如何分配handler?

  http包中的一段源码

func (srv *Server) Serve(l net.Listener) error {
	if fn := testHookServerServe; fn != nil {
		fn(srv, l) // call hook with unwrapped listener
	}

	origListener := l
	l = &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 failure

	ctx := context.WithValue(baseCtx, ServerContextKey, srv)
	for {
		rw, err := l.Accept()
		if err != nil {
			select {
			case <-srv.getDoneChan():
				return ErrServerClosed
			default:
			}
			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 := ctx
		if cc := srv.ConnContext; cc != nil {
			connCtx = cc(connCtx, rw)
			if connCtx == nil {
				panic("ConnContext returned nil")
			}
		}
		tempDelay = 0
		c := srv.newConn(rw)
		c.setState(c.rwc, StateNew, runHooks) // before Serve can return
		go c.serve(connCtx)
	}
}

  

  Go是通过一个函数 ListenAndServe 来处理这些事情的,这个底层其实这样处理的:初始化一个server对象,然后调用了 net.Listen("tcp", addr) ,也就是底层 用TCP协议搭建了一个服务,然后监控我们设置的端口。

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

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

 

 

 

 

 

 

 

 

 

 

 

 

    

标签:Web,err,请求,nil,--,srv,Go,服务器,客户端
From: https://www.cnblogs.com/99kol/p/17380319.html

相关文章

  • DX12 实战 法线贴图
    前言本篇将展示如何使用DX12实现normalmap源代码chenglixue/D3D12atnormalmap要点定义:法线贴图基于凹凸贴图衍生出来的。纹理贴图中的纹素是RGB颜色值,而法线贴图中的纹素是法向量的坐标用途:计算光照,在纹理图中存储法向量,再将其带入光照计算。在避免高模建模的情况下......
  • Java守护线程daemon介绍
    1.介绍线程分为用户线程和守护线程JVM必须确保用户线程执行完毕,但是不用等待守护线程执行完毕示例代码:publicclassTestDaemon{publicstaticvoidmain(String[]args){DaemonThreaddaemon=newDaemonThread();CustomerThreadcustomer=ne......
  • Unity常用事件函数
    1publicclassEventFunction:MonoBehaviour2{3publicfloatattackValue=10000;4publicfloatcurrentHP;56//对变量赋值的顺序(左边最先赋值,右边最后赋值,以此类推):7//变量声明并直接赋值>检视面板赋值>Awake>OnEnable>Start>外部赋......
  • 面试考核点
    参考:架构设计面试精讲  https://www.bilibili.com/video/BV1R34y1Z7dG?p=3&vd_source=898d5514be58985430a49b46d5500c13   常见面试套路常见面试问题分类提升面试竞争力,需具备的三个技术认识是什么?很多人对职业发展规划是新学了某种技术,某个框架。实际应提升的是......
  • 列表单元素访问,超索引报错
    >>>lst[1,2,3,(3,'hj'),9]>>>lst[3](3,'hj')>>>lst[4:4][]>>>lst[4:5][9]>>>lst[4:6][9]>>>lst[6:7][]>>>lst.insert(7,9)#7超过最大索引,不会真正插入在第八个位置,而是插入在尾......
  • Apifox与注解
    注解 支持的类型 支持的请求类型 支持的Content-Type 请求示例@PathVariable url GET 所有 /test/{id}@RequestParam url GET 所有 /test?id=1Body POST/PUT/DELETE/PATCH form......
  • 好奇心: 保持对未知世界用不停息的热情
    2023第三本书,之前下决心每次读完书就要写一篇读后感,加深认识。结果下决心后的第一本《乡土中国》就写不下来读后感,感觉读后感太多太密,还不如想起来的时候回头浏览一遍书。但是最近听路障的视频,发现他也建议写读后感来增加对书的认识,这样能更好的帮助记忆,加上这本书好奇心里面......
  • 合并去重脚本
    importsys#f1=""#f2=""#f3=""##打印命令行参数#iflen(sys.argv)>4:#f1=sys.argv[1]#f2=sys.argv[2]#f3=sys.argv[3]unique_lines=set()withopen('/tmp/jitang.txt','r'......
  • THUSC2023 游记
    THUSC2023游记Day1试机,试机题是A+B,一个交互,一个提答。提答是几何,瞬间不想认真做了。键盘的下键是坏的,按下去弹不起来,左键也是,但没下键那么严重。喊工作人员换键盘,工作人员说明天作为随机打乱,不管了。交互写了个暴力,发现分数给错了,除以了100(试了下各种错误,比如越界,sqrt(-......
  • Java游戏任务背包系统设计思路
    前言在游戏开发中,游戏任务系统是必不可少的,因为任务系统是游戏的驱动,是使玩家能坚持玩下去的途径之一,也是玩家的目标。任务大体分为三块,玩家接受任务--进行任务--任务完成获得奖励。这里面包括两个系统,任务系统和背包系统,因为玩家获得的奖励需要落到玩家自己的背包里。所以我们......