Go语言基础与实战案例 | 青训营笔记

39 阅读4分钟

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

Go基础知识

什么是Go语言

  1. 高性能、高并发:
  2. 语法简单、学习曲线平缓
  3. 丰富的标准库
  4. 完善的工具链:编译、代码格式化、错误检查、帮助文档、代码补充提示、单元测试框架、性能优化
  5. 静态编译:所有的编译结构默认都是静态链接的,只需要拷贝唯一一个可执行文件,不需要部署运行
  6. 快速编译
  7. 跨平台:在路由器和树莓派上也可运行,可以适配交叉编译环境
  8. 垃圾回收

变量

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 代理

1.jpg

v1-TCP echo server

main函数里用net.listen去监听一个端口,返回一个server,在一个死循环里面,每次去accept一个请求,成功就会返回一个链接,接下里及叜process中去处理这个链接。

在process函数中defer connection.close(),可以字啊函数退出的时候把这个链接关掉,否则会有资源的泄露。

bufio.NewReader来创建一个带缓冲的只读流,可以减少底层系统调用的次数。

v2-auth

修改process函数,读出协议,认证的方法,最后用curl命令来进行测试。

v3-请求阶段

实现一个connect函数,包含这六个字段

  1. VER 版本号,socks5的值为0x05

  2. CMD 0x01表示CONNECT请求

  3. RSV 保留字段,值为0x00

  4. ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。

    1. 0x01表示IPv4地址,DST.ADDR为4个字节
    2. 0x03表示域名,DST.ADDR是一个可变长度的域名
  5. DST.ADDR 一个可变长度的值

  6. 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即可。