go语言基础学习 | 青训营笔记

71 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

一、环境搭建

参考掘金课程链接

1、安装 Go 语言

访问 go.dev/ ,点击 Download ,下载windows安装包,安装完成后配置环境变量 需要配置GOPATH(go语言工作区,即代码存放区)和PATH两个变量。 最后可根据cmd 输入 go env 来验证是否安装成功。参考链接

2、在vscode 中配置go语言开发环境

  • 安装go插件并重启vscode

image.png

  • 访问 github 速度比较慢,配置了 go mod proxy,参考 goproxy.cn/ 里面的描述配置,下载第三方依赖包的速度可以大大加快

3、下载课程示例代码

image.png 克隆时出现错误:Recv failure: Connection was reset

解决方法

  • 进入课程示例项目代码目录,运行 go run example/01-hello/main.go 如果正确输出 hello world,则说明环境配置正确

二、go基础语法

课程讲的太过简略,系统学习过再行整理。

三、相关实例

1、猜数字

  • 题目: 预先设定一个secretNum, 用户输入数字进行猜测,程序告知输入数据是否大于或者小于secretNUm, 不断循环直到猜出数字。
  • 逻辑简单,主要知识点有:
    • a. 随机数的产生(用时间戳初始化随机种子)
    maxNum := 100
    //用时间戳来初始化随机数种子
    rand.Seed(time.Now().UnixNano())
    secretNumber := rand.Intn(maxNum)
    
    
    • b.输入数据的读取和输入
    reader := bufio.NewReader(os.Stdin)
    

2、 在线词典

  • 题目:调用第三方查询英文词典并输出
  • 算法流程: 查看第三方请求命令->转化为代码->自定义输入参数->查看第三方响应json包->转化为结构体->反序列json->输出需要的数据
  • 主要知识点:
    • a. HTTP请求: 网页 右键检查,查看network的代码

image.png

buf, err := json.Marshal((request))//序列化

err = json.Unmarshal(bodyText, &dictResponse)//反序列

3、socks5代理服务器实现

  • 题目:SOKS5协议是代理协议,采用明文传输,历史比较久远,诞生于互联网早期。它的用途是,比如某些企业的内网为了确保安全性,有很严格的防火墙策略,但是带来的副作用就是访问某些资源会很麻烦。socks5 相当于在防火墙开了个口子,让授权的用户可以通过单个端口去访问内部的所有资源。
  • 实现原理

image.png

  • 工作阶段 首先是浏览器和 socks5代理建立 TCP 连接,代理再和真正的服务器建立 TCP 连接。这里可以分成四个阶段,握手阶段、认证阶段、请求阶段、relay 阶段
  1. 握手阶段:浏览器会向socks5代发送请求,包的内容包括一个协议的版本,还有支持的认证的种类,socks5 服务器会选中一个认证方式,返回给浏览器。如果返回的是 0 的话就代表不需要认证,返回其他类型的话会开始认证流程

读取请求: image.png

返回请求:

	//返回请求
	// +----+--------+
	// |VER | METHOD |
	// +----+--------+
	// | 1  |   1    |
	// +----+--------+
	_, err = conn.Write([]byte{socks5Ver, 0x00})
	if err != nil {
		return fmt.Errorf("write failed:%w", err)
	}
	return nil
  1. 认证阶段
  2. 请求,认证通过之后浏览器会向 soks5 服务器发请求,主要信息包括版本号,请求的类型,一般主要是connection 请求,就代表代理服务器要和某域名或者某个IP 地址某个端口建立 TCP 连接.代理服务器收到响应之后,会真正和后端服务器建立连接,然后返回一个响应。

读取connection请求


// +----+-----+-------+------+----------+----------+
	// |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
	// +----+-----+-------+------+----------+----------+
	// | 1  |  1  | X'00' |  1   | Variable |    2     |
	// +----+-----+-------+------+----------+----------+
	// VER 版本号,socks5的值为0x05
	// CMD 0x01表示CONNECT请求
	// RSV 保留字段,值为0x00
	// ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。
	//   0x01表示IPv4地址,DST.ADDR为4个字节
	//   0x03表示域名,DST.ADDR是一个可变长度的域名
	// DST.ADDR 一个可变长度的值
	// DST.PORT 目标端口,固定2个字节

服务器返回响应

//返回响应
	// +----+-----+-------+------+----------+----------+
	// |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
	// +----+-----+-------+------+----------+----------+
	// | 1  |  1  | X'00' |  1   | Variable |    2     |
	// +----+-----+-------+------+----------+----------+
	// VER socks版本,这里为0x05
	// REP Relay field,内容取值如下 X’00’ succeeded
	// RSV 保留字段
	// ATYPE 地址类型
	// BND.ADDR 服务绑定的地址
	// BND.PORT 服务绑定的端口DST.PORT
	_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})

  1. rely 阶段,此浏览器会发送正常发送请求,然后服务器接收之后,会直接把请求转化到真正的服务器上,然后如果真得服务器返回请求、那么也会转换到浏览器上。实际上代理服务器并不关心流量的细节,可以是 HTTP流量,也可以是其它 TCP 流量。
//双向数据传送

	//浏览器到服务器
	go func() {
		_, _ = io.Copy(dest, reader)
		cancel()
	}()

	//服务器到浏览器
	go func() {
		_, _ = io.Copy(conn, dest)
		cancel()
	}()
  • 测试结果 运行该程序后,在cmd中执行 curl --socks5 127.0.0.1:1080(代理服务器地址) -v www.qq.com (访问链接), 可打印出相关log image.png image.png 这里注意windows是在cmd中运行curl, 且之前开了vpn, 导致结果跑不出来,后来关了vpn, 则可以,原因不详。

参考链接

⁢​‌⁡‬​⁡⁣​⁢⁤‍⁣​​‌‌‍‬‍​⁤⁡‬​‌⁤⁢​⁢‌⁢‌‍⁢​⁤‍⁣‬‌‌⁤‍​Go 语言上手 - 基础语法 .pptx - 飞书云文档 (feishu.cn)