这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
Go基础知识
什么是Go语言
- 高性能、高并发:
- 语法简单、学习曲线平缓
- 丰富的标准库
- 完善的工具链:编译、代码格式化、错误检查、帮助文档、代码补充提示、单元测试框架、性能优化
- 静态编译:所有的编译结构默认都是静态链接的,只需要拷贝唯一一个可执行文件,不需要部署运行
- 快速编译
- 跨平台:在路由器和树莓派上也可运行,可以适配交叉编译环境
- 垃圾回收
变量
go语言中有变量的声明有两种方式:
一种是 var name string =""
这种方式来声明变量,声明变量会自动推导变量的类型,不过也可以显示
写出变量类型。
另一种声明变量的方式是:使用变量 冒号:= 等于值
if else
go里面if是没有括号的,后面直接接大括号
循环
go里面是没有while循环和do while循环,只有唯一的一种for循环
Switch
在go里case中是不需要加break的,相比于c或c++,go的switch功能更强大,可以使用任意的变量类型
猜谜游戏
v1 版本 secretNumber := rand.Intn(maxNum)
,发现每次生成的随机数都是一模一样的
v2版本通过指定随机数种子,实现生成的随机数不同 rand.Seed(time.Now().UnixNano())
不指定随机数种子的话,每次随机出来的结果都是一样的,一般选择当前的时间戳作为随机数种子。
v3版本通过对输入的信息进行处理,并将输入的内容去掉换行转换为int类型
v4版本加了一些提示,用来提示玩家输入的数比生成的随机数大还是小,但是问题在于这样玩家只能进行一次操作。
v5版本将v4版本中的return替换成了continue,只有在真正猜中的时候才会return
这几个版本实现了go语言的变量、循环、函数控制流、错误处理。
命令行词典
代码模块主要分为创建请求、设置请求头、发起请求和读取响应四个部分。
v1版本输出的结果是一大串json字符串,并没有对结果进行序列化
v2版本创建DictRequest结构体,并通过json.Marshal来序列化这个结构体数组
v3版本将返回的结果进行反序列化json.Unmarshal(bodyText, &dictResponse)
(注意不能漏掉&符号,需要将结果写入dictResponse),将request的内容进行序列化同理,也是需要定义一个DictResponse
结构体,因为代码量蛮大可以使用oktools代码生成工具。
v4版本对请求的错误代码进行处理,对于返回状态码不是200的请求进行处理
sockets5 代理
v1-TCP echo server
main函数里用net.listen去监听一个端口,返回一个server,在一个死循环里面,每次去accept一个请求,成功就会返回一个链接,接下里及叜process中去处理这个链接。
在process函数中defer connection.close()
,可以字啊函数退出的时候把这个链接关掉,否则会有资源的泄露。
bufio.NewReader
来创建一个带缓冲的只读流,可以减少底层系统调用的次数。
v2-auth
修改process函数,读出协议,认证的方法,最后用curl命令来进行测试。
v3-请求阶段
实现一个connect函数,包含这六个字段
-
VER 版本号,socks5的值为0x05
-
CMD 0x01表示CONNECT请求
-
RSV 保留字段,值为0x00
-
ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。
- 0x01表示IPv4地址,DST.ADDR为4个字节
- 0x03表示域名,DST.ADDR是一个可变长度的域名
-
DST.ADDR 一个可变长度的值
-
DST.PORT 目标端口,固定2个字节
通过make相应长度的buf去填充我们想要读取的内容buf := make([]byte, 4) _, err := io.ReadFull(reader, buf)
v4-relay阶段
用net.dial
建立一个TCP连接,建立完连接之后同样需要一个defer来关闭链接,然后建立浏览器和下游服务器的双向数据转发,启动两个goroutinue 以及标准库的io.copy
利用标准库里的context机制,用context连with cancel来创建一个context,在最后等待ctx.Done
,主要cancel被调用,ctx.Done
就会立刻返回,然后两个goroutinue里面就只用调用一次cancel即可。