这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
我是先写完了后面的课堂知识部分,再按照课堂笔记模板硬套,所以层级没那么清晰,为了阅读方便就先把内容较短的、个人理解相关的放前面了
个人总结部分
本节重点
- Go 语言是什么及基础语法讲解
- 三个蛮有意思的实战,分别涉及
- 基础交互、读写、随机数
- 抓包、json序列化与反序列化
- 网络编程
课后小结
课程还是挺有意思的,知识点很密集,侥幸于自己至少预习了语法。笔记越做越觉得是不是有点没必要……之后会尝试更简洁地记录自己重点需要关注的部分。另外读代码既需要记录,又不好直接发布,再看看吧
以下是知识记录
什么是 Go 语言
- 高性能、高并发
- 不需要寻找高性能第三方库,使用标准库或基于标准库的第三方库即可完成高性能、高并发开发
- 语法简单、学习曲线平缓
- 基于 C 语言并大量简化,上手容易
- 丰富的标准库
- 完善的工具链
- 编译、注释、测试、包管理等等都有内置工具,支持单元测试等
- 静态链接
- 不需要像 java 那样附加 JRE
- 快速编译
- 跨平台
- 无需配置交叉编译环境
- 垃圾回收
配置环境略去
基础语法
hello, world
package main // main包 -> 程序入口包,这个文件就是程序的入口文件
import (
"fmt" // 格式化输入输出
)
func main() {
fmt.Println("hello world")
}
switch 分支
switch var1 {
case val1:
...
case val2:
...
case val3, val4 :
...
default:
...
}
- 相比C或Java,Go的
switch更强大,var1可以是包括字符串在内的任意数据类型,val1和val2则可以是同类型的任意值 - Java中若没有
break,会一直执行到最后,Go中不会- switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用
fallthrough
- switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用
- 可以同时测试多个可能符合条件的值,使用逗号分割它们,如
val3,val4
切片
Go 语言切片是对数组的抽象
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片 ("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大
感觉类似 Arraylist
声明
// 声明一个未指定大小的数组来定义切片
var identifier []type
// 使用 make() 函数来创建切片
var slice1 []type = make([]type, len)
// 也可以简写为
slice1 := make([]type, len)
Append 小tips
s = append(s,"d") -> 执行 append 可能扩容并产生新切片,需要重新赋值回切片 s
切片其他
指针
Go 中的指针相比起来没有那么强大,主要用在修改拷贝参数
在 main 中直接调用 add2 将不起作用
其他
还讲了 变量声明,
if else,for, 数组,map, 结构体,错误处理, 字符串操作, 字符串和数值类型转换, 格式化输入输出, 时间, 进程 等,都是比较基础的东西,略去
实战 remark
生成随机数
如果不使用 rand.Seed() 来初始化随机数种子,每次运行结果都是一样的;这里使用时间戳初始化
package main
import (
"fmt"
"math/rand"
)
func main() {
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNumber)
}
结果会在 0-100 中间
在线词典
抓包
首先抓包,在 彩云小译 进行测试。点击翻译后,在 network 选项卡的 dict (请求方法为 request) 能解析出我们需要的数据
请求这么一大堆信息会很麻烦,我们用一些奇巧淫技
使用 cURL
右键我们需要的请求,复制为 cURL
会返回一大堆命令。到这个网站 复制粘贴这些命令并选择 go 语言,自动返回一个函数
复制到 IDE 中,发现有几行有错误,删掉即可
代码部分如下
可以输出一大串 Json
Json 序列化
序列化是将对象状态转换为可保持或传输的格式的过程
现在发送的请求是固定的,我们需要设置变量并 序列化 来改变请求
在 Go 中,构造与json字段名称相同的结构体并调用json.Marshal即可
type DictRequest struct {
TransType string `json:"trans_type"`
Source string `json:"source"`
UserID string `json:"user_id"`
}
request := DictRequest{TransType: "en2zh", Source: "good"}
buf, err := json.Marshal(request)
注意Marshal返回的是个byte数组而非真正的字符串,需要 var data = bytes.NewReader(buf) 而非之前的 var data = strings.NewReader({"trans_type":"en2zh","source":"good"})
解析 response
Go 可以像 js 或 python 那样用 [] 或 . 取值,但不是最佳实践。更常用的方式应该是和 request 一样去写一个结构体,然后再把返回的 json 字段反序列化到结构体内
但是,我们可以发现……这 json 太复杂了要一个个定义 structure 不如让程序员去死。所以我们同样用奇巧淫技(代码生成)
把浏览器复制的字段再复制过来,点击 转换-嵌套 (转换-展开 得到多个独立结构体,这里没有必要),复制到我们程序中即可
我们试着不再 print 全部,而是只打印需要的、解析好的:
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
// 解释部分是个数组,我们循环打印
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
}
添加检测问题的模块,若状态码不是两百,报错
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
最后,改变代码,从 Args 拿到 word,把 word 设为查询的参数即可,具体步骤略去
Socks5 代理
完成 TCP echo
windows 日常要装一堆东西才能跑,心态小崩,晚点试试 WSL
参考这个看代码,讲解的蛮清楚了。注意在 process 中要关闭连接再继续, 执行完回到无限循环后重新开始新的连接
完成 SOCKS
看代码吧
- 认证:浏览器会给代理服务器发送报文,会有三个字段,我们判断这三个字段是否合法,并返回一个包,告诉浏览区我们选择哪种方式
- 请求:接受浏览器发回的报文并一个个读出,得到要去建立连接的地址和端口号并回包
- relay:建立连接、建立双向数据转发(浏览器拷贝到服务器,服务器拷贝到浏览器);注意默认异步直接跳到结束,需要
context.WithCancel等待