go语言基础---8

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

Http请求报文格式分析

package main

import (
	"fmt"
	"net"
)

func main() {

	//监听
	listener, err := net.Listen("tcp", ":8000")
	if err != nil {
		fmt.Println("listener err", err)
		return
	}

	defer listener.Close()
	//阻塞等待用户的连接
	conn, err := listener.Accept()
	if err != nil {
		fmt.Println("Accept err = ", err)
		return
	}

	defer conn.Close()

	//接收客户端的数据
	buf := make([]byte, 1024*4)

	readSize, err := conn.Read(buf)

	if readSize == 0 { //对方断开,出问题了
		fmt.Println("Read err = ", err)
		return
	}

	fmt.Printf("#%v#", string(buf[:readSize]))

}
#GET / HTTP/1.1 //请求行
Host: 127.0.0.1:8000
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Chromium";v="116", "Not)A;Brand";v="24", "Microsoft Edge";v="116"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 Edg/116.0.1938.69
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6

#

go语言基础---8,golang,iphone,开发语言

HTTP编程

go语言标准库内建提供了net/http包,涵盖了HTTP客户端和服务端的具体实现。使用net/http包,我们可以很方便地编写HTTP客户端或服务端的程序。

func ListenAndServe(addr string, handler Handler) error

ListenAndServe监听TCP地址addr,并且会使用handler参数调用Serve函数处理接收到的连接。handler参数一般会设为nil,此时会使用DefaultServeMux。
go语言基础---8,golang,iphone,开发语言文章来源地址https://www.toymoban.com/news/detail-708956.html

package main

import "net/http"

// HandleConn 第一个参数,给客户端回复数据,req 读取客户端发送的数据
func HandleConn(w http.ResponseWriter, req *http.Request) {
	_, err := w.Write([]byte("hello go")) //给客户端回复数据
	if err != nil {
		return
	}
}

func main() {
	//HandleFunc注册一个处理器函数handler和对应的模式pattern(注册到DefaultServeMux)。
	//ServeMux的文档解释了模式的匹配机制。
	//注册处理函数,用户连接,自动调用指定的处理函数
	//func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
	http.HandleFunc("/", HandleConn)

	//监听绑定
	//ListenAndServe监听TCP地址addr,
	//并且会使用handler参数调用Serve函数处理接收到的连接。handler参数一般会设为nil,此时会使用DefaultServeMux。
	http.ListenAndServe(":8000", nil)
}

http服务器获取客户端的一些信息

type Request struct {
    // Method指定HTTP方法(GET、POST、PUT等)。对客户端,""代表GET。
    Method string
    // URL在服务端表示被请求的URI,在客户端表示要访问的URL。
    //
    // 在服务端,URL字段是解析请求行的URI(保存在RequestURI字段)得到的,
    // 对大多数请求来说,除了Path和RawQuery之外的字段都是空字符串。
    // (参见RFC 2616, Section 5.1.2)
    //
    // 在客户端,URL的Host字段指定了要连接的服务器,
    // 而Request的Host字段(可选地)指定要发送的HTTP请求的Host头的值。
    URL *url.URL
    // 接收到的请求的协议版本。本包生产的Request总是使用HTTP/1.1
    Proto      string // "HTTP/1.0"
    ProtoMajor int    // 1
    ProtoMinor int    // 0
    // Header字段用来表示HTTP请求的头域。如果头域(多行键值对格式)为:
    //	accept-encoding: gzip, deflate
    //	Accept-Language: en-us
    //	Connection: keep-alive
    // 则:
    //	Header = map[string][]string{
    //		"Accept-Encoding": {"gzip, deflate"},
    //		"Accept-Language": {"en-us"},
    //		"Connection": {"keep-alive"},
    //	}
    // HTTP规定头域的键名(头名)是大小写敏感的,请求的解析器通过规范化头域的键名来实现这点。
    // 在客户端的请求,可能会被自动添加或重写Header中的特定的头,参见Request.Write方法。
    Header Header
    // Body是请求的主体。
    //
    // 在客户端,如果Body是nil表示该请求没有主体买入GET请求。
    // Client的Transport字段会负责调用Body的Close方法。
    //
    // 在服务端,Body字段总是非nil的;但在没有主体时,读取Body会立刻返回EOF。
    // Server会关闭请求的主体,ServeHTTP处理器不需要关闭Body字段。
    Body io.ReadCloser
    // ContentLength记录相关内容的长度。
    // 如果为-1,表示长度未知,如果>=0,表示可以从Body字段读取ContentLength字节数据。
    // 在客户端,如果Body非nil而该字段为0,表示不知道Body的长度。
    ContentLength int64
    // TransferEncoding按从最外到最里的顺序列出传输编码,空切片表示"identity"编码。
    // 本字段一般会被忽略。当发送或接受请求时,会自动添加或移除"chunked"传输编码。
    TransferEncoding []string
    // Close在服务端指定是否在回复请求后关闭连接,在客户端指定是否在发送请求后关闭连接。
    Close bool
    // 在服务端,Host指定URL会在其上寻找资源的主机。
    // 根据RFC 2616,该值可以是Host头的值,或者URL自身提供的主机名。
    // Host的格式可以是"host:port"。
    //
    // 在客户端,请求的Host字段(可选地)用来重写请求的Host头。
    // 如过该字段为"",Request.Write方法会使用URL字段的Host。
    Host string
    // Form是解析好的表单数据,包括URL字段的query参数和POST或PUT的表单数据。
    // 本字段只有在调用ParseForm后才有效。在客户端,会忽略请求中的本字段而使用Body替代。
    Form url.Values
    // PostForm是解析好的POST或PUT的表单数据。
    // 本字段只有在调用ParseForm后才有效。在客户端,会忽略请求中的本字段而使用Body替代。
    PostForm url.Values
    // MultipartForm是解析好的多部件表单,包括上传的文件。
    // 本字段只有在调用ParseMultipartForm后才有效。
    // 在客户端,会忽略请求中的本字段而使用Body替代。
    MultipartForm *multipart.Form
    // Trailer指定了会在请求主体之后发送的额外的头域。
    //
    // 在服务端,Trailer字段必须初始化为只有trailer键,所有键都对应nil值。
    // (客户端会声明哪些trailer会发送)
    // 在处理器从Body读取时,不能使用本字段。
    // 在从Body的读取返回EOF后,Trailer字段会被更新完毕并包含非nil的值。
    // (如果客户端发送了这些键值对),此时才可以访问本字段。
    //
    // 在客户端,Trail必须初始化为一个包含将要发送的键值对的映射。(值可以是nil或其终值)
    // ContentLength字段必须是0或-1,以启用"chunked"传输编码发送请求。
    // 在开始发送请求后,Trailer可以在读取请求主体期间被修改,
    // 一旦请求主体返回EOF,调用者就不可再修改Trailer。
    //
    // 很少有HTTP客户端、服务端或代理支持HTTP trailer。
    Trailer Header
    // RemoteAddr允许HTTP服务器和其他软件记录该请求的来源地址,一般用于日志。
    // 本字段不是ReadRequest函数填写的,也没有定义格式。
    // 本包的HTTP服务器会在调用处理器之前设置RemoteAddr为"IP:port"格式的地址。
    // 客户端会忽略请求中的RemoteAddr字段。
    RemoteAddr string
    // RequestURI是被客户端发送到服务端的请求的请求行中未修改的请求URI
    // (参见RFC 2616, Section 5.1)
    // 一般应使用URI字段,在客户端设置请求的本字段会导致错误。
    RequestURI string
    // TLS字段允许HTTP服务器和其他软件记录接收到该请求的TLS连接的信息
    // 本字段不是ReadRequest函数填写的。
    // 对启用了TLS的连接,本包的HTTP服务器会在调用处理器之前设置TLS字段,否则将设TLS为nil。
    // 客户端会忽略请求中的TLS字段。
    TLS *tls.ConnectionState
}
package main

import (
	"fmt"
	"net/http"
)

// HandleConn 第一个参数,给客户端回复数据,req 读取客户端发送的数据
func HandleConn(w http.ResponseWriter, req *http.Request) {

	fmt.Println("r.Method = ", req.Method) //r.Method =  GET
	fmt.Println("r.URL = ", req.URL)       // /
	fmt.Println("Header = ", req.Header)
	fmt.Println("Body = ", req.Body)

	_, err := w.Write([]byte("hello go")) //给客户端回复数据
	if err != nil {
		return
	}
}

func main() {
	//HandleFunc注册一个处理器函数handler和对应的模式pattern(注册到DefaultServeMux)。
	//ServeMux的文档解释了模式的匹配机制。
	//注册处理函数,用户连接,自动调用指定的处理函数
	//func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
	http.HandleFunc("/", HandleConn)

	//监听绑定
	//ListenAndServe监听TCP地址addr,
	//并且会使用handler参数调用Serve函数处理接收到的连接。handler参数一般会设为nil,此时会使用DefaultServeMux。
	http.ListenAndServe(":8000", nil)
}

http客户端编程

type Response struct {
    Status     string // 例如"200 OK"
    StatusCode int    // 例如200
    Proto      string // 例如"HTTP/1.0"
    ProtoMajor int    // 例如1
    ProtoMinor int    // 例如0
    // Header保管头域的键值对。
    // 如果回复中有多个头的键相同,Header中保存为该键对应用逗号分隔串联起来的这些头的值
    // (参见RFC 2616 Section 4.2)
    // 被本结构体中的其他字段复制保管的头(如ContentLength)会从Header中删掉。
    //
    // Header中的键都是规范化的,参见CanonicalHeaderKey函数
    Header Header
    // Body代表回复的主体。
    // Client类型和Transport类型会保证Body字段总是非nil的,即使回复没有主体或主体长度为0。
    // 关闭主体是调用者的责任。
    // 如果服务端采用"chunked"传输编码发送的回复,Body字段会自动进行解码。
    Body io.ReadCloser
    // ContentLength记录相关内容的长度。
    // 其值为-1表示长度未知(采用chunked传输编码)
    // 除非对应的Request.Method是"HEAD",其值>=0表示可以从Body读取的字节数
    ContentLength int64
    // TransferEncoding按从最外到最里的顺序列出传输编码,空切片表示"identity"编码。
    TransferEncoding []string
    // Close记录头域是否指定应在读取完主体后关闭连接。(即Connection头)
    // 该值是给客户端的建议,Response.Write方法的ReadResponse函数都不会关闭连接。
    Close bool
    // Trailer字段保存和头域相同格式的trailer键值对,和Header字段相同类型
    Trailer Header
    // Request是用来获取此回复的请求
    // Request的Body字段是nil(因为已经被用掉了)
    // 这个字段是被Client类型发出请求并获得回复后填充的
    Request *Request
    // TLS包含接收到该回复的TLS连接的信息。 对未加密的回复,本字段为nil。
    // 返回的指针是被(同一TLS连接接收到的)回复共享的,不应被修改。
    TLS *tls.ConnectionState
}
package main

import (
	"fmt"
	"net/http"
)

func main() {
	response, err := http.Get("http://www.baidu.com")
	if err != nil {
		fmt.Println("Get response err = ", err)
		return
	}

	defer response.Body.Close() //内容在body里面

	fmt.Println("response.status = ", response.Status)         //response.status =  200 OK
	fmt.Println("response.StatusCode = ", response.StatusCode) //200
	fmt.Println("response.Header = ", response.Header)
	//fmt.Println("response.Body = ", response.Body) //response.Body =  &{[] 0xc000226080 <nil> <nil>}
	buf := make([]byte, 4*1024)
	var tmp string
	for true {
		BodySize, err := response.Body.Read(buf)
		if BodySize == 0 {
			fmt.Println("read err = ", err)
			break
		}
		tmp += string(buf[:BodySize])
	}

	fmt.Println("tmp = ", tmp)
}

单任务百度贴吧小爬虫

package main

import (
	"fmt"
	"net/http"
	"os"
	"strconv"
)

// https://tieba.baidu.com/f?kw=%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F&ie=utf-8&pn=150

// HttpGet 爬取网页内容
func HttpGet(url string) (result string, err error) {
	response, err1 := http.Get(url)
	if err1 != nil {
		err = err1
		return
	}

	defer response.Body.Close()

	//读取网页body
	buf := make([]byte, 1024*4)

	for true {
		readSize, err := response.Body.Read(buf)
		if readSize == 0 { //读取结束,或者出问题
			fmt.Println("response body read err = ", err)
			break
		}
		result += string(buf[:readSize])
	}

	return
}

func DoWork(start, end int) {
	fmt.Printf("正在爬取%d到%d的页面\n", start, end)

	//明确目标(要知道你准备在那个范围或者网站去搜索)
	for i := start; i <= end; i++ {
		//strconv.Itoa((i-1)*50)//整型转string
		url := "https://tieba.baidu.com/f?kw=%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F&ie=utf-8&pn=" + strconv.Itoa((i-1)*50)
		fmt.Println("url =", url)
		//爬(将所有的网站的内容全部爬下来)
		result, err := HttpGet(url)
		if err != nil {
			fmt.Println("HttpGet err = ", err)
			continue
		}

		//把内容写入到文件
		fileName := strconv.Itoa(1) + ".html"
		file, err := os.Create(fileName)
		if err != nil {
			fmt.Println("create err = ", err)
			continue
		}

		_, err1 := file.WriteString(result)
		if err1 != nil {
			fmt.Println("write string err = ", err)
			continue
		} //写内容
		err2 := file.Close()
		if err2 != nil {
			fmt.Println("close err = ", err2)
			continue
		} //关闭文件
	}
}
func main() {
	var start, end int
	fmt.Println("请输入起始页(>=1):")
	fmt.Scan(&start)
	fmt.Println("请输入终止页(>=起始页):")
	fmt.Scan(&end)

	DoWork(start, end)
}

并发版网络爬虫

package main

import (
	"fmt"
	"net/http"
	"os"
	"strconv"
)

// https://tieba.baidu.com/f?kw=%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F&ie=utf-8&pn=150

// HttpGet 爬取网页内容
func httpGet1(url string) (result string, err error) {
	response, err1 := http.Get(url)
	if err1 != nil {
		err = err1
		return
	}

	defer response.Body.Close()

	//读取网页body
	buf := make([]byte, 1024*4)

	for true {
		readSize, err := response.Body.Read(buf)
		if readSize == 0 { //读取结束,或者出问题
			fmt.Println("response body read err = ", err)
			break
		}
		result += string(buf[:readSize])
	}

	return
}

// 爬取一个网页
func SpiderPage(i int, page chan int) {
	//strconv.Itoa((i-1)*50)//整型转string
	url := "https://tieba.baidu.com/f?kw=%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F&ie=utf-8&pn=" + strconv.Itoa((i-1)*50)
	fmt.Printf("真正爬%d页的网页:%s\n", i, url)
	//爬(将所有的网站的内容全部爬下来)
	result, err := httpGet1(url)
	if err != nil {
		fmt.Println("HttpGet err = ", err)
		return
	}

	//把内容写入到文件
	fileName := strconv.Itoa(i) + ".html"
	file, err := os.Create(fileName)
	if err != nil {
		fmt.Println("create err = ", err)
		return
	}

	_, err1 := file.WriteString(result)
	if err1 != nil {
		fmt.Println("write string err = ", err)
		return
	} //写内容
	err2 := file.Close()
	if err2 != nil {
		fmt.Println("close err = ", err2)
		return
	} //关闭文件

	page <- i //写i
}
func doWork1(start, end int) {
	fmt.Printf("正在爬取%d到%d的页面\n", start, end)
	page := make(chan int)
	//明确目标(要知道你准备在那个范围或者网站去搜索)
	for i := start; i <= end; i++ {
		go SpiderPage(i, page)
	}

	for i := start; i <= end; i++ {
		fmt.Printf("第%d个页面爬取完成\n", <-page)
	}
}
func main() {
	var start, end int
	fmt.Println("请输入起始页(>=1):")
	fmt.Scan(&start)
	fmt.Println("请输入终止页(>=起始页):")
	fmt.Scan(&end)

	doWork1(start, end)
}

到了这里,关于go语言基础---8的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【Go 基础篇】Go语言包详解:模块化开发与代码复用

    在Go语言中, 包(Package) 是一种用于组织代码的机制,用于将相关的函数、类型和变量等组织在一起,以便于模块化开发和代码复用。包的使用能够使程序结构更加清晰、可维护性更高,同时也是Go语言强调的一项重要特性。本篇博客将深入探讨Go语言中包的相关知识,包括

    2024年02月11日
    浏览(15)
  • go语言从0基础到安全项目开发实战

    搭建环境比较简单 到以下链接下 Go下载 - Go语言中文网 - Golang中文社区 下载windows版本64位zip包 https://studygolang.com/dl/golang/go1.20.7.windows-amd64.zip 不配置的话就只能在bin目录下才能运行go命令 创建test.go文件 然后代码如下 编译运行  两种方式编译运行代码 1.先 go build test.go编译成

    2024年02月13日
    浏览(26)
  • Go语言 -- Web开发基础学习 net/http包

    Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。 Go语言最擅长的领域就是Web开发,此贴是本人入门完go语法基础后学习Web开发的学习笔记。 新建go文件hello_world.go 写入: 在命令行运行: go run ./hello_world.go 可以发现控制台输出以下信息 通过上述代码

    2024年02月06日
    浏览(30)
  • 【go语言基础】go中的方法

    先思考一个问题,什么是方法,什么是函数? 方法是从属于某个结构体或者非结构体的。在func这个和方法名中间加了一个特殊的接收器类型,这个接收器可以是结构体类型的或者是非结构体类型的。从属的结构体获取该方法。 函数则没有这种从属关系。 小结: 大多

    2024年02月13日
    浏览(17)
  • Go语言基础

    参考书籍《Go程序设计语言》 学习Go语言基础,并记录相关知识和代码。 创建helloworld.go 输出命令行参数 使用range简化 使用Join简化 版本二,文件与命令行 go 可以方便的创建服务器,并且有并发性。 Go并发获取多个URL 简单服务器 带有并发锁的计数服务器 显示相关协议与表单

    2024年02月11日
    浏览(27)
  • Go语言基础(一)

    本文档参考golang官方文档以及一些教程书籍,若文档有错误,欢迎issue 🤗 https://go.dev/doc/tutorial/ 参考书籍《Go语言开发实战》 Go语言是Google公司发布的一种静态型、编译型的开源编程语言,是新时代的 C语言 。Go语言已经成为 云计算时代 的重要基础编程语言。 2012年3月28日,

    2024年02月06日
    浏览(22)
  • go语言基础---8

    go语言标准库内建提供了net/http包,涵盖了HTTP客户端和服务端的具体实现。使用net/http包,我们可以很方便地编写HTTP客户端或服务端的程序。 ListenAndServe监听TCP地址addr,并且会使用handler参数调用Serve函数处理接收到的连接。handler参数一般会设为nil,此时会使用DefaultServeMux。

    2024年02月09日
    浏览(17)
  • Go语言基础知识(一):基础介绍

    Go 语言又称 Golang,由 Google 公司于 2009 年发布,近几年伴随着云计算、微服务、分布式的发展而迅速崛起,跻身主流编程语言之列,和 Java 类似,它是一门静态的、强类型的、编译型编程语言,为并发而生,所以天生适用于并发编程(网络编程)。 目前 Go 语言支持 Windows、

    2024年02月13日
    浏览(28)
  • Go语言基础之切片

    切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。 切片是一个引用类型,它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合 声明切片类型的基本语法如下: 其中, name:表示变

    2024年02月11日
    浏览(30)
  • Go语言基础快速上手

    Go中没有明确意思上的 enum (枚举)定义,不过可以借用 iota 标识符实现一组自增常亮值来实现枚举类型。 切片(slice) 本身不是动态数组或动态指针。只是它内部采用数组存储数据,当数组长度达到数组容量时,会进行 动态扩容 。 大白话就是切片功能和Java中的List集合类似,

    2024年01月20日
    浏览(19)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包