这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
Go语言实战
1.猜字谜游戏
生成随机数
package main
import (
"fmt"
"math/rand"
)
func main() {
maxNum := 100
secretNum := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNum)
}
执行结果:
始终是81结果需要对其进行改进(设置随机数种子)
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
maxNum := 100
//设置随机数种子
rand.Seed(time.Now().UnixNano())
secretNum := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNum)
}
读取用户输入
通过使用reader流进行读取用户的输入,同时以换行符为分界完成对输入筛选,同时进行分割,进行转为整数
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
maxNum := 100
//设置随机数种子
rand.Seed(time.Now().UnixNano())
secretNum := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNum)
fmt.Println("Please input your guess: ")
//使用流处理
reader := bufio.NewReader(os.Stdin)
//读取一行输入
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("error occur", err)
return
}
//去掉换行符
input = strings.TrimSuffix(input, "\n")
//转为整形
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("error guesss input", err)
return
}
fmt.Println("your guess:", guess)
}
对其添加相应的猜字谜循环代码,完成逻辑操作
func main() {
maxNum := 100
//设置随机数种子
rand.Seed(time.Now().UnixNano())
secretNum := rand.Intn(maxNum)
fmt.Println("The secret number is ", secretNum)
fmt.Println("Please input your guess: ")
//使用流处理
reader := bufio.NewReader(os.Stdin)
for {
//读取一行输入
input, err := reader.ReadString('\n')
if err != nil {
fmt.Println("error occur", err)
//修改为continue
continue
}
//去掉换行符
input = strings.TrimSuffix(input, "\n")
//转为整形
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("error guesss input", err)
continue
}
fmt.Println("your guess:", guess)
//完成比大小
if guess < secretNum {
fmt.Println("your guess number is smaller")
} else if guess > secretNum {
fmt.Println("your guess number is bigger")
} else {
fmt.Println("Correct,you legend!")
break;
}
}
}
The secret number is 26
Please input your guess:
20
your guess: 20
your guess number is smaller
21
your guess: 21
your guess number is smaller
22
your guess: 22
your guess number is smaller
23
your guess: 23
your guess number is smaller
24
your guess: 24
your guess number is smaller
25
your guess: 25
your guess number is smaller
26
your guess: 26
Correct,you legend!
在线词典介绍
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
type AutoGenerated struct {
Rc int `json:"rc"`
Wiki struct {
KnownInLaguages int `json:"known_in_laguages"`
Description struct {
Source string `json:"source"`
Target interface{} `json:"target"`
} `json:"description"`
ID string `json:"id"`
Item struct {
Source string `json:"source"`
Target string `json:"target"`
} `json:"item"`
ImageURL string `json:"image_url"`
IsSubject string `json:"is_subject"`
Sitelink string `json:"sitelink"`
} `json:"wiki"`
Dictionary struct {
Prons struct {
EnUs string `json:"en-us"`
En string `json:"en"`
} `json:"prons"`
Explanations []string `json:"explanations"`
Synonym []string `json:"synonym"`
Antonym []string `json:"antonym"`
WqxExample [][]string `json:"wqx_example"`
Entry string `json:"entry"`
Type string `json:"type"`
Related []interface{} `json:"related"`
Source string `json:"source"`
} `json:"dictionary"`
}
func main() {
client := &http.Client{}
var data = strings.NewReader(`{"trans_type":"en2zh","source":"good","user_id":"6327e3ab1dafa9001339ea84"}`)
//创建请求头
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
//设置请求头
req.Header.Set("authority", "api.interpreter.caiyunai.com")
req.Header.Set("accept", "application/json, text/plain, */*")
req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
req.Header.Set("app-name", "xy")
req.Header.Set("content-type", "application/json;charset=UTF-8")
req.Header.Set("device-id", "")
req.Header.Set("origin", "https://fanyi.caiyunapp.com")
req.Header.Set("os-type", "web")
req.Header.Set("os-version", "")
req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
req.Header.Set("sec-ch-ua", `"Not_A Brand";v="99", "Microsoft Edge";v="109", "Chromium";v="109"`)
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("sec-ch-ua-platform", `"Windows"`)
req.Header.Set("sec-fetch-dest", "empty")
req.Header.Set("sec-fetch-mode", "cors")
req.Header.Set("sec-fetch-site", "cross-site")
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.52")
req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
//发起请求
resp, err := client.Do(req)
//异常处理 请求
if err != nil {
log.Fatal(err)
}
//手动关闭流
defer resp.Body.Close()
//读取响应
bodyText, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", bodyText)
var dictResponse AutoGenerated
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
fmt.Println("error :", err)
log.Fatal(err)
}
fmt.Printf("%#v\n", dictResponse)
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
}
}
Socks5代理服务器
Socks5原理图如下:
实现步骤
1.TCP echo server 服务器搭建
实现的功能:发送什么,我就回复什么
代码实现:
package main
import (
"bufio"
"log"
"net"
)
func main() {
server, err := net.Listen("tcp", "127.0.0.1:1080")
// err
if err != nil {
panic(err)
}
// while
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
}
}
}
测试:
mine:project/ $ nc 127.0.0.1 1080
hello
hello
第一阶段认证阶段:
代码如下:
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
)
const sock5Ver = 0x05
const cmdBind = 0x01
const atypIPV4 = 0x01
const atypeHOST = 0x03
const atypeIPV6 = 0x04
func main() {
server, err := net.Listen("tcp", "127.0.0.1:1080")
// err
if err != nil {
panic(err)
}
// while
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)
err := auth(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
log.Println("auth success")
}
func auth(reader *bufio.Reader, conn net.Conn) (err error) {
ver, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read ver failed:%w", err)
}
if ver != sock5Ver {
return fmt.Errorf("not supported ver : %w", ver)
}
methodSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read methodSize failed:%w", err)
}
method := make([]byte, methodSize)
_, err = io.ReadFull(reader, method)
if err != nil{
return fmt.Errorf("read method failed : %w",err)
}
log.Println("ver",ver,"method",method)
_,err = conn.Write([]byte{sock5Ver,0x00})
if err != nil{
return fmt.Errorf("write failed : %w",err)
}
return nil
}
测试结果:
2023/01/19 20:34:19 ver 5 method [0 1]
2023/01/19 20:34:19 auth success
mine:project/ $ curl --socks5 127.0.0.1:1080 -v http://www.qq.com
* Trying 127.0.0.1:1080...
* TCP_NODELAY set
* SOCKS5 communication to www.qq.com:80
* SOCKS5 connect to IPv4 101.91.42.232:80 (locally resolved)
* Failed to receive SOCKS5 connect request ack.
* Closing connection 0
curl: (7) Failed to receive SOCKS5 connect request ack.
请求阶段,获取要访问的连接的ip和端口
package main
import (
"bufio"
"encoding/binary"
"errors"
"fmt"
"io"
"log"
"net"
)
const sock5Ver = 0x05
const cmdBind = 0x01
const atypIPV4 = 0x01
const atypeHOST = 0x03
const atypeIPV6 = 0x04
func main() {
server, err := net.Listen("tcp", "127.0.0.1:1080")
// err
if err != nil {
panic(err)
}
// while
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)
err := auth(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
log.Println("auth success")
err = connect(reader, conn)
if err != nil {
log.Printf("client %v out failed:%v", conn.RemoteAddr(), err)
return
}
}
func auth(reader *bufio.Reader, conn net.Conn) (err error) {
ver, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read ver failed:%w", err)
}
if ver != sock5Ver {
return fmt.Errorf("not supported ver : %w", ver)
}
methodSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read methodSize failed:%w", err)
}
method := make([]byte, methodSize)
_, err = io.ReadFull(reader, method)
if err != nil {
return fmt.Errorf("read method failed : %w", err)
}
log.Println("ver", ver, "method", method)
_, err = conn.Write([]byte{sock5Ver, 0x00})
if err != nil {
return fmt.Errorf("write failed : %w", err)
}
return nil
}
func connect(reader *bufio.Reader, conn net.Conn) (err error) {
buf := make([]byte, 4)
_, err = io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("reader header failed:%w", err)
}
ver, cmd, atyp := buf[0], buf[1], buf[3]
if ver != sock5Ver {
return fmt.Errorf("not support ver : %w", ver)
}
if cmd != cmdBind {
return fmt.Errorf("not support cmd : %w", cmd)
}
addr := ""
switch atyp {
case atypIPV4:
_, err = io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("read atyp failed : %w", err)
}
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
case atypeHOST:
hostSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("host size failed : %w", err)
}
host := make([]byte, hostSize)
_, err = io.ReadFull(reader, host)
if err != nil{
return fmt.Errorf("read host failed : %w",err)
}
addr = string(host)
case atypeIPV6:
return errors.New("IPV6 : not support now")
default:
return errors.New("unkown atyp")
}
_,err = io.ReadFull(reader,buf[:2])
if err != nil{
return fmt.Errorf("read port failed : %w",err)
}
port := binary.BigEndian.Uint16(buf[:2])
log.Println("dial",addr,port)
//给与回复
_,err = conn.Write([]byte{0x05,0x00,0x00,0x01,0,0,0,0,0,0})
if err != nil{
return fmt.Errorf("write failed : %w",err)
}
return nil
}
测试:
2023/01/19 22:35:21 ver 5 method [0 1]
2023/01/19 22:35:21 auth success
2023/01/19 22:35:21 dial 101.91.42.232 80
根据上述的结果可以看到,系统完成了获取到了访问的ip地址和端口
mine:project/ $ curl --socks5 127.0.0.1:1080 -v http://www.qq.com
* Trying 127.0.0.1:1080...
* TCP_NODELAY set
* SOCKS5 communication to www.qq.com:80
* SOCKS5 connect to IPv4 101.91.42.232:80 (locally resolved)
* SOCKS5 request granted.
* Connected to 127.0.0.1 (127.0.0.1) port 1080 (#0)
> GET / HTTP/1.1
> Host: www.qq.com
> User-Agent: curl/7.68.0
> Accept: */*
>
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact
curl: (52) Empty reply from server
最后一部代理阶段的relay阶段
需要和真正的服务器建立TCP连接
最终代码如下:
package main
import (
"bufio"
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"log"
"net"
)
const sock5Ver = 0x05
const cmdBind = 0x01
const atypIPV4 = 0x01
const atypeHOST = 0x03
const atypeIPV6 = 0x04
func main() {
server, err := net.Listen("tcp", "127.0.0.1:1080")
// err
if err != nil {
panic(err)
}
// while
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)
err := auth(reader, conn)
if err != nil {
log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)
return
}
log.Println("auth success")
err = connect(reader, conn)
if err != nil {
log.Printf("client %v out failed:%v", conn.RemoteAddr(), err)
return
}
}
func auth(reader *bufio.Reader, conn net.Conn) (err error) {
ver, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read ver failed:%w", err)
}
if ver != sock5Ver {
return fmt.Errorf("not supported ver : %w", ver)
}
methodSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read methodSize failed:%w", err)
}
method := make([]byte, methodSize)
_, err = io.ReadFull(reader, method)
if err != nil {
return fmt.Errorf("read method failed : %w", err)
}
log.Println("ver", ver, "method", method)
_, err = conn.Write([]byte{sock5Ver, 0x00})
if err != nil {
return fmt.Errorf("write failed : %w", err)
}
return nil
}
func connect(reader *bufio.Reader, conn net.Conn) (err error) {
buf := make([]byte, 4)
_, err = io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("reader header failed:%w", err)
}
ver, cmd, atyp := buf[0], buf[1], buf[3]
if ver != sock5Ver {
return fmt.Errorf("not support ver : %w", ver)
}
if cmd != cmdBind {
return fmt.Errorf("not support cmd : %w", cmd)
}
addr := ""
switch atyp {
case atypIPV4:
_, err = io.ReadFull(reader, buf)
if err != nil {
return fmt.Errorf("read atyp failed : %w", err)
}
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
case atypeHOST:
hostSize, err := reader.ReadByte()
if err != nil {
return fmt.Errorf("host size failed : %w", err)
}
host := make([]byte, hostSize)
_, err = io.ReadFull(reader, host)
if err != nil {
return fmt.Errorf("read host failed : %w", err)
}
addr = string(host)
case atypeIPV6:
return errors.New("IPV6 : not support now")
default:
return errors.New("unkown atyp")
}
_, err = io.ReadFull(reader, buf[:2])
if err != nil {
return fmt.Errorf("read port failed : %w", err)
}
port := binary.BigEndian.Uint16(buf[:2])
dest, err := net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port))
if err != nil {
return fmt.Errorf("dial dst failed : %w", err)
}
//关闭连接协议
defer dest.Close()
log.Println("dial", addr, port)
//给与回复
_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
if err != nil {
return fmt.Errorf("write failed : %w", err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
//双向的数据传输
go func() {
_, _ = io.Copy(dest, reader)
cancel()
}()
go func() {
_, _ = io.Copy(conn, dest)
}()
//等待执行完成
<-ctx.Done()
return nil
}
测试结果:
运行后:
mine:project/ $ curl --socks5 127.0.0.1:1080 -v http://www.qq.com
* Trying 127.0.0.1:1080...
* TCP_NODELAY set
* SOCKS5 communication to www.qq.com:80
* SOCKS5 connect to IPv4 101.91.22.57:80 (locally resolved)
* SOCKS5 request granted.
* Connected to 127.0.0.1 (127.0.0.1) port 1080 (#0)
> GET / HTTP/1.1
> Host: www.qq.com
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 302 Moved Temporarily
< Server: stgw
< Date: Thu, 19 Jan 2023 15:03:01 GMT
< Content-Type: text/html
< Content-Length: 137
< Connection: keep-alive
< Location: https://www.qq.com/
<
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>stgw</center>
</body>
</html>
* Connection #0 to host 127.0.0.1 left intact
测试结果:
`2023/01/19 23:03:01 ver 5 method [0 1]
2023/01/19 23:03:01 auth success
2023/01/19 23:03:01 dial 101.91.22.57 80`