Go语言的实战案例 | 青训营笔记

141 阅读4分钟

这是我参与【第五届青训营】伴学笔记创作活动的第1天|(二)

一、本堂课重点内容

Go实战案例,练习

二、实战案例

1、猜谜语游戏

1-生成随机数

**注意:先设置随机数种子,否则生成的随机数序列相同 **

rand.Seed(time.Now().UnixNano())

package main

import (
   "fmt"
   "math/rand"
   "time"
)

func main() {
   maxNum := 100
   rand.Seed(time.Now().UnixNano())
   secretNumber := rand.Intn(maxNum)
   fmt.Println("The secret number is", secretNumber)
}

看看运行效果对比:

【未设置随机数种子】 image.png

生成的随机数相同

【设置随机数种子】

image.png

设置之后,生成的随机数都在0-100之间,且不一样

2-读取用户输入

添加以下代码

// 读取用户输入
fmt.Println("Please input your guess")
reader := bufio.NewReader(os.Stdin)
input, err := reader.ReadString('\n')
if err != nil{
   fmt.Println("An error occured while reading input.Please try again", err)
   return
}
// 去掉\n
input = strings.TrimSuffix(input, "\n")

// 转为数字
guess, err := strconv.Atoi(input)
if err != nil{
   fmt.Println("Invalid input.Please enter an integer value")
   return
}
fmt.Println("You guess is", guess)

运行效果

image.png

3-实现判断逻辑

// 判断逻辑
if guess > secretNumber {
   fmt.Println("Your guess is bigger than the secret number. Please try again")
} else if guess < secretNumber {
   fmt.Println("Your guess is smaller than the secret number. Please try again")
} else {
   fmt.Println("Correct, you Legend!")
}

运行效果

image.png

4-添加循环

func main() {
   maxNum := 100
   rand.Seed(time.Now().UnixNano())
   secretNumber := rand.Intn(maxNum)
   //fmt.Println("The secret number is", secretNumber)

   // 读取用户输入
   fmt.Println("Please input your guess")
   reader := bufio.NewReader(os.Stdin)
   for {
      input, err := reader.ReadString('\n')
      if err != nil {
         fmt.Println("An error occured while reading input.Please try again", err)
      return
         continue
      }
      // 去掉\n
      input = strings.TrimSuffix(input, "\n")

      // 转为数字
      guess, err := strconv.Atoi(input)
      if err != nil {
         fmt.Println("Invalid input.Please enter an integer value")
      return
         continue
      }
      fmt.Println("You guess is", guess)

      // 判断逻辑
      if guess > secretNumber {
         fmt.Println("Your guess is bigger than the secret number. Please try again")
      } else if guess < secretNumber {
         fmt.Println("Your guess is smaller than the secret number. Please try again")
      } else {
         fmt.Println("Correct, you Legend!")
         break
      }
   }
}

运行效果

image.png

2、在线词典

介绍:用户可以在命令行里面查询一个单词,我们能通过第三方的API查询到单词的翻译并打印出来。

1-抓包

网址 : fanyi.caiyunapp.com/

输入“你好”,点击翻译,浏览器会发送一系列请求,翻译单词的请求是“dict”,是http的post请求。 json里面有两个字段,source是要查询的单词。

image.png

2-golang代码生成

在golang中发送post请求,代码构造比较麻烦,可以在浏览器中通过右键浏览器里面的copy as curl,copy完成之后在终端粘贴一个curl命令,可以成功返回一大串json。

image.png

复制之后粘贴到网站:curlconverter.com/go/

image.png

复制go代码到编辑器中,有几个header比较复杂,生成代码有转义导致的编译错误,删掉即可

运行:

image.png

3-生成request body

生成一段JSON,常用的方式是先构造一个结构体:

image.png 这里定义一个变量,初始化每个结构体成员,再调用json.Marshal来得到这个序列化之后的字符串,不过这里是字节数组,所以后面使用bytes.NewReader来构造request上的body,其他的代码不变。

运行:

image.png

4-解析response body

将上一步运行出来的代码复制到oktools.net/json2go 网址:

image.png

将response结构体复制到编译器中并修改以下代码

image.png

运行:

image.png

5-打印结果

image.png

3、SOCKS5代理服务器

SOCKS5协议是代理协议,但不能用来翻墙,它的协议都是明文传输

1-TCP echo server

工作逻辑:客户端发送什么就回复什么

讲解:首先在 main 函数里面先用 net.listen 去监听一个端口,会返回一个 server,然后在一个死循环里面,每次去 accept 一个请求,成功就会返回一个连接。接下来的话我们在一个 process 函数里面去处理这个连接。接下来是这个 process 函数的实现,首先第一步的话会先加一个 deferconnection.close0),defer 是 Golang 里面的一个语法,这一行的含义就是代表在这个函数退出的时候要把这个连接关掉,否则会有资源的泄露。用 bufio.NewReader 来创建一个 带缓冲的只读流,这个在前面的猜迷游戏里面也有用到,带缓冲的流的作用是,可以减少底层系统调用的次数,比如这里为了方便是一个字节个字节的读取,但是底层可能合并成几次大的读取操作。并且带缓冲的流会有更多的一些工具函数用来读取数据。我们可以简单地调用那个 readbyte 函数来读取单个字节,再把这一个字节写进去连接。

package main

import (
   "bufio"
   "log"
   "net"
)

func main() {
   server, err := net.Listen("tcp", "127.0.0.1:1080")
   if err != nil {
      panic(err)
   }
   for {
      client, err := server.Accept()
      if err != nil {
         log.Printf("Accept failed %v", err)
         continue
      }
      go process(client)
   }
}

func process(conn net.Conn) {
   defer conn.Close()
   reader := bufio.NewReader(conn)
   for {
      b, err := reader.ReadByte()
      if err != nil {
         break
      }
      _, err = conn.Write([]byte{b})
      if err != nil {
         break
      }
   }
}

当发生错误端口被占用时:

image.png image.png

2-auth

认证阶段 image.png

3-请求阶段

读取携带url或者ip地址+端口的包,然后把它打印出来

image.png

4-relay阶段

直接用net.Dial建立一个TCP连接,defer关闭连接

image.png

三、课后个人总结

跟着写了几个实战例子,多练练还可以。

四、课程链接学习

Go 语言的实战案例