Golang中基于HTTP协议的网络服务

这篇具有很好参考价值的文章主要介绍了Golang中基于HTTP协议的网络服务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基于HTTP协议的网络服务

一、HTTP协议的网络服务

HTTP协议是基于TCP/IP协议栈的,并且它也是一个面向普通文本的协议。

只要搞清楚了HTTP请求的报文(报文的头部(header)和主体(body))应该包含的内容,使用任何一个文本编译器,就饿可以编写一个完整的HTTP请求报文。

在这种情况下,直接使用net.Dial函数,就可以。

使用net/http代码包中的程序实体,可以更便捷的访问基于HTTP协议的网络服务。其中最便捷的是使用http.Get函数。

1.1 使用http.Get函数访问HTTP协议的网络服务

package main

import (
	"fmt"
	"net/http"
)

func main() {
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	response1, err := http.Get(url1)
	if err != nil {
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

http.Get函数会返回两个结果值:

  • 第一个结果值的类型是*http.Response,它是网络服务给我们传回来的响应内容的结构化表示。
  • 第二个结果值是error类型。它代表了在创建和发送HTTP请求,以及接受和解析HTTP响应的过程中可能发生的错误。

http.Get函数内部会使用缺省的HTTP客户端,并调用它的Get方法以完成功能。缺省客户端类型是*http.Client,由公开变量DefaultClient代表。

1.2 使用缺省客户端DefaultClient(类型为*http.Client

package main

import (
	"fmt"
	"net/http"
)

func main() {
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	// response1, err := http.Get(url1)
	response1, err := http.DefaultClient.Get(url1)
	if err != nil {
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

它的基本类型(http.Client)可以开箱即用。

1.3 使用http.Client访问HTTP协议的网络服务

package main

import (
	"fmt"
	"net/http"
)

func main() {
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	// response1, err := http.Get(url1)
	// response1, err := http.DefaultClient.Get(url1)
	var oneClient http.Client
	response1, err := oneClient.Get(url1)
	if err != nil {
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

http.Client是一个结构体类型,并且它包含的字段是公开的。之所以该类型的零值仍然可以使用,是因为它的这些字段要么存在着响应的缺省值,要么其零值直接可以使用,且代表着特定的含义。

二、http.Client中的Transport字段

http.Client类型中的Transport字段代表着:向网络服务发送HTTP请求,并从网络服务接收HTTP响应的操作过程。

Transport字段的RoundTrip方法实现单次HTTP事务(或者说基于HTTP协议的单词交互)需要的所有步骤。

Transport 字段是http.RoundTrip接口类型,它有一个缺省值,这个缺省值的变量名为DefaultTransport。DefaultTransport的实际类型为*http.Transport*http.Transport可以被复用,并且是线程安全的。

如果没有显式的为http.Client中的Transport字段赋值,这个Client就会直接使用DefaultTransport。

http.Client中的Timeout字段,代表前面所说的单词HTTP事务的超时时间,它是time.Duration类型,它的零值是可用的,用于表示没有设置超时时间。

(1)http.Transport类型中的DialContext字段

http.Transport类型,在内部使用一个net.Dialer类型的值,并且会把该值的Timeout字段的值,设定为30秒。

也就是说,这个Dialer值如果在30秒内还没有建立好网络连接,那么就会被判定为操作超时。

在DefaultTransport的值被初始化的时候,这样的Dialer值的DialContext方法会被赋给前者的DialContext字段:

var DefaultTransport RoundTripper = &Transport{
	Proxy: ProxyFromEnvironment,
	DialContext: defaultTransportDialContext(&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}),
	ForceAttemptHTTP2:     true,
	MaxIdleConns:          100,
	IdleConnTimeout:       90 * time.Second,
	TLSHandshakeTimeout:   10 * time.Second,
	ExpectContinueTimeout: 1 * time.Second,
}

func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
	return dialer.DialContext
}

KeepAlive的背后是一种针对网络连接(更确切地说,是TCP连接)的存活探测机制。它的值用于表示每隔多长时间发送一次探测包。当该值不大于0时,则表示不开启这种机制。

DefaultTransport会把这个字段的值设定为30秒。

(2)http.Transport类型中的其它字段

一些是关于超时操作

  • IdleConnTimeout:含义是空闲的连接在多久之后就应该关闭。

    DefaultTransport 会把该字段的值设定为90秒。

    如果该值为0,那么就表示不关闭空闲连接。注意,这样可能会造成资源的泄露。

  • ResponseHeaderTimeout:含义是,从客户端把请求完全递交给操作系统到从操作系统那里接收到响应报文头到最长时长。

    DefaultTransport并没有设定该字段的值。

  • ExpectContinueTimeout:含义是,在客户端提交了请求报文头之后,等待接收第一个响应报文头的最长时间。

    DefaultTransport 把该字段的值设定为1秒。

    在客户端想要使用HTTP的“POST”方法把一个很大的报文体发送给服务端的时候,它可以先通过发送一个包含了“Expect: 100-continue”的请求报文头,来询问服务端是否愿意接受这个大报文体。这个字段就是用于设定在这种情况下的超时时间的。

    注意,如果该字段的值不大于0,那么无论多大的请求报文体都将会被立即发送出去。

  • TLSHandshakeTimeout:TLS是Transport Layer Security 的缩写,可以被翻译为传输层安全。这个字段代表了基于TLS协议的连接在被建立时的握手阶段的超时时间。

    DefaultTransport 把该字段的值设置为10秒。

    若该值为0,则表示对这个值不设限。

一些与IdleConnTimeout相关的字段值

  • MaxIdleConns:用于控制访问所有主机的最大空闲连接。如果为0,不做限制。

    DefaultTransport 把MaxIdleConns设定为100。

    MaxIdleConns字段只会对空闲连接的总数做出限定。

  • MaxIdleConnsPerHost: 控制Transport值访问每一个网络服务的最大空闲连接数。如果为0,将使用缺省值2, 这个缺省值由DefaultMaxIdleConnsPerHost所代表。

    也就是说,默认情况下,对于某一个Transport值访问的每一个网络服务,它的空闲连接数都最多只能由两个。

  • MaxConnsPerHost:针对某一个Transport值访问的每一个网络服务的最大连接数,不论这些连接是否是空闲的。

    该字段没有缺省值,零值表示不限定。

MaxIdleConnsMaxIdleConnsPerHost两个与空闲连接数有关的字段的值应该是联动的,所以,有时需要根据实际情况定制它们,可以参考DefaultTransport变量的声明。

三、为什么会出现空闲的连接

3.1 空闲连接的产生

HTTP协议有一个请求报文头,叫做“Connection”。在HTTP协议的1.1 版本中,这个报文头的值默认是“keep-alive”。

在这种情况下,网络连接都是持久连接,它们会在当前的HTTP事务完成后仍然保持着连通性,因此是可以被复用的。

连接的可复用,带来两种可能:

  • 一种可能是,针对同一个网络服务,有新的HTTP请求被提交,该连接被再次使用。
  • 另一种可能是,不再有对该网络服务的HTTP请求,该连接被闲置。(产生空闲的连接)

后一种情况就产生了空闲连接。另外,如果分配给某一个网络服务的连接过多的话,也可能会导致空闲连接的产生。因为每一个新递交的HTTP请求,都只会征用一个空闲的连接。所以,为空闲连接设定限制,在大多数情况下都是很有必要的,也是需要斟酌的。

3.2 杜绝空闲连接的产生

如果想彻底杜绝空闲连接的产生,那么可以在初始化的时候,把它的DisableKeepAlives字段的值设定为true。这时,HTTP请求的“Connection”报文头的值就会被设置为“close”。这会告诉网络服务,这个网络连接不必保持,当前的HTTP事务完成后就可以断开它。

如此一来,每当一个HTTP请求被递交时,就会产生一个新的网络连接。这样做会明显地加重网络服务以及客户端的负载。所以,在一般情况下,我们都不要去设置这个DisableKeepAlive字段。

net.Dialer类型中,也有一个看起来很相似的字段KeepAlive。不过,它与前面所说的HTTP 持久连接不是一个概念,KeepAlive是直接作用在底层的socket上的。

KeepAlive的背后是一种针对网络连接(更确切地说,是TCP连接)的存活探测机制。它的值用于表示每隔多长时间发送一次探测包。当该值不大于0时,则表示不开启这种机制。DefaultTransport会把这个字段的值设定为30秒。

四、http.Server

http.Server类型与http.Client相对应。http.Server代表的是基于HTTP协议的服务端,或者网络服务。

4.1 http.Server类型的ListenAndServe方法

http.Server类型的ListenAndServe方法的功能是:监听一个基于TCP协议的网络地址,并对接收到的HTTP请求进行处理。

  • 这个方法默认会开启针对网络连接的存活探测机制,以保证连接是持久的。

  • 同时,该方法会一直执行,直到有严重的错误发生或被外界关掉。

    当被外界关掉时,它会返回一个由http.ErrServerClosed变量代表的错误值。

4.2 ListenAndServe方法主要做的事情

func (srv *Server) ListenAndServe() error {
	if srv.shuttingDown() {
		return ErrServerClosed
	}
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(ln)
}

ListenAndServe方法主要会做下面的事情:

  1. 检查当前的http.Server类型的值的Addr字段。

    该字段的值代表了当前的网络服务需要使用的网络地址。即:IP地址和端口号。如果这个字段的值为空字符串,那么就用":http"代替。

    也就是说,使用任何可以代表本机的域名和IP地址,并且端口号为80.

  2. 通过调用net.Listen函数在已确定的网络地址上启动基于TCP协议的监听。

  3. 检查net.Listen 函数返回的错误值。

    如果该错误值不为nil,那么就直接返回该值。否则,通过调用当前值的Serve方法准备接受和处理将要到来的HTTP请求。

4.3 (衍生问题)net.Listen 函数都做了哪些事情

net.Listen函数做的事情:

  1. 解析参数值中包含的网络地址隐含的IP地址和端口号;

  2. 根据给定的网络协议,确定监听的方法,并开始进行监听;

    这里还可以延伸到net.socket函数,以及socket相关的知识。

4.4 (衍生问题)http.Server类型的Serve方法是怎么接受和处理HTTP请求的

在一个for循环中,网络监听的Accept方法会被不断的调用,

	for {
		rw, err := l.Accept()
  }

该方法会返回两个结果值:

  • 第一个结果值是net.Conn 类型,代表包含了新到来的HTTP请求的网络连接;

  • 第二个结果值是error类型值,代表可能发生的错误。

    如果错误不为nil,除非它代表了一个暂时性的错误,否则循环都会被终止。如果是暂时性的错误,那么循环的下一次迭代将会在一段时间之后开始执行。

如果这里的Accept方法没有返回非nil的错误值,那么这里的程序将会把它的第一个结果值包装成一个*http.conn类型的值,然后通过在新的goroutine中调用这个*http.conn 类型值的serve方法,来对当前的HTTP请求进行处理。

HTTP请求相关的,更多的衍生问题:

  • 这个*http.conn类型值的状态有几种,分别代表着处理的哪个阶段?
  • 处理的过程中会用到哪些读取器和写入器,它们的作用分别是什么?
  • 这里的程序是怎么调用我们自定义的处理函数的?

五、思考:怎么优雅地停止基于HTTP协议的网络服务程序?

srv.Shutdown(context.Background()) 的方式停止服务,通过RegisterOnShutdown可添加服务停止时的调用。文章来源地址https://www.toymoban.com/news/detail-408623.html

到了这里,关于Golang中基于HTTP协议的网络服务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【网络进阶】HTTP服务器(一)

    HTTP(超文本传输协议,Hypertext Transfer Protocol)是一种用于传输超文本数据(如HTML、图片、视频等)的应用层协议。它允许互联网上的客户端和服务器之间通过请求和响应进行双向通信。HTTP 是互联网的基石,为 Web 浏览器和 Web 服务器之间的数据交换提供了标准规范。 HTTP 基

    2024年02月02日
    浏览(48)
  • 哈工大计算机网络课程网络层协议之:网络层服务概述

    网络层提供的主要功能包括: 从发送主机向接收主机传送数据段(Segment) 发送主机:将数据段封装到数据报(datagram)中 接收主机:向传输层交付数据段(Segment) 每个主机和路由器都运行网络层协议 路由器检验所有穿越它的IP数据报的头部域,决策如何处理IP数据报。 需

    2024年02月12日
    浏览(44)
  • 计算机网络-分层结构,协议,接口,服务

    发送文件前要做的准备工作很多 把这个准备工作分层小问题解决,也就分层解决 每层相互独立,每层做的工作不同 界面自然清晰,层与层之间的接口能够体现层之间的关系同时要简洁明了,不用太多接口了 同一层对应的对等实体进行的操作是相反的 只有下层为上层提供服

    2024年01月22日
    浏览(46)
  • [C++ 网络协议] 多进程服务器端

    具有代表性的并发服务器端实现模型和方法: 多进程服务器:通过创建多个进程提供服务。✔ 多路复用服务器:通过捆绑并统一管理I/O对象提供服务。 多线程服务器:通过生成与客户端等量的线程提供服务。 目录 1. 进程的概念及应用 1.1 什么是进程? 1.2 创建进程 1.2.1 进程

    2024年02月11日
    浏览(37)
  • Go语言的TCP和HTTP网络服务基础

    目录 【TCP Socket 编程模型】 Socket读操作 【HTTP网络服务】 HTTP客户端 HTTP服务端 TCP/IP 网络模型实现了两种传输层协议:TCP 和 UDP,其中TCP 是面向连接的流协议,为通信的两端提供稳定可靠的数据传输服务;UDP 提供了一种无需建立连接就可以发送数据包的方法。实现网络编程,

    2024年02月12日
    浏览(49)
  • Go语言的网络编程与HTTP服务

    Go语言(Golang)是Google开发的一种静态类型、垃圾回收、并发简单的编程语言。Go语言的设计目标是让程序员更容易编写并发程序,并在多核处理器上充分发挥性能。Go语言的网络编程和HTTP服务是其核心功能之一,可以轻松地构建高性能、可扩展的网络应用程序。 在本文中,我们

    2024年02月19日
    浏览(87)
  • 6.2.5 网络基本服务----动态主机配置协议DHCP

    6.2.5 网络基本服务----动态主机配置协议DHCP 动态主机配置协议允许一台计算机加入新的网络时可自动获取网络配置信息,不用人工参与。连网的计算机需要配置的参数包括 IP地址 子网掩码 默认路由器的IP地址 域名服务器IP地址 DHCP与DNS、FTP、Telnet一样也采用客户服务器模式。

    2024年02月16日
    浏览(39)
  • 网络层IP协议中的协议号&传输层端口号对应的服务

    ip协议是网络层协议,三层的, 协议号标识上层是什么协议 ,eg:17号表示是上层即传输层是udp协议,6号表示上层即传输层是tcp协议,89标识上层是ospf协议等等 按端口号可分为2大类: 1、公认端口(Well-KnownPorts):范围从0到1023。 2、动态端口(Dynamic Ports):范围从1024到65

    2023年04月26日
    浏览(35)
  • Java 网络编程 —— 创建非阻塞的 HTTP 服务器

    HTTP 客户程序必须先发出一个 HTTP 请求,然后才能接收到来自 HTTP 服器的响应,浏览器就是最常见的 HTTP 客户程序。HTTP 客户程序和 HTTP 服务器分别由不同的软件开发商提供,它们都可以用任意的编程语言编写。HTTP 严格规定了 HTTP 请求和 HTTP 响应的数据格式,只要 HTTP 服务器

    2024年02月06日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包