当前位置: 首页 > news >正文

web网站开发实训报告seo网络推广师招聘

web网站开发实训报告,seo网络推广师招聘,seo关键词优化培训班,新手做网站做那个👂 Take me Hand Acoustic - Ccile Corbel - 单曲 - 网易云音乐 第3个小项目有问题,不能在Windows下跑,懒得去搜Linux上怎么跑了,已经落下进度了.... 目录 😳前言 🍉Go两小时 🔑小项目实战 …

👂 Take me Hand Acoustic - Cécile Corbel - 单曲 - 网易云音乐

第3个小项目有问题,不能在Windows下跑,懒得去搜Linux上怎么跑了,已经落下进度了....

目录

😳前言

🍉Go两小时

🔑小项目实战

🐘猜数字游戏

🐘在线词典

代码1  --  抓包

代码2  --  生成request body 

代码3  --  解析 response body

代码4  --  打印结果

代码6  --  完整代码

cmd测试

🐘Socks5代理服务器

🔑介绍

📚原理

💻TCP echo server

🚢auth

🏘请求阶段

🤪relay阶段

 📚Hertz框架


😳前言

注意!run时,要点func main()左边的绿色▲,而不是右上方的虫子和▲

注意2~ 一个文件夹下,只能有一个main.go文件,比如这样👇

学Go,除了字节内部课,还需要一套B站全流程的新手入门视频,只是内部课的话,节奏比较快,虽然也是有视频事无巨细地教,但有些点小白还是不懂的,需要到B站新手视频处查阅,需要一遍又一遍bing,Google,百度,GPT,stackOverFlow,youtube,B站(一共7个工具,记好了,加上算法群,项目群,在职群....效率不会低的)

还需要很多文档...

🍉Go两小时

注意先安装Goland,Git,弄个Github学生认证,免费使用

跟着敲一遍(182行代码),先有个印象👇

从 Java 的角度初识 Go 语言 | 青训营笔记 - HikariLan's Blog (minecraft.kim)

跟着敲完180行入门代码还不过瘾的话,再跟👇这个5小时教程,巩固一下基础

【golang教学】第二章:golang的基础知识——结构,包,变量初探(1010工作室出品)_哔哩哔哩_bilibili

代码 -- 复制可运行

package mainimport ("errors""fmt""time"
)import (_ "errors"
)// 错误处理
func findUser(users []user, name string) (v *user, err error) {for _, u := range users {if u.name == name {return &u, nil}}return nil, errors.New("not found")
}func add(a int, b int) int {return a + b //函数要写在主函数外
}func add2(n int) {n += 2
}func add2ptr(n *int) {*n += 2
}type user struct {name     stringpassword string
}// 检查用户密码是否匹配
func (u user) checkPassword(password string) bool {return u.password == password
}// 充值密码, 指针结构体
func (u *user) resetPassword(password string) {u.password = password
}func main() {var a int = 1var b, c int = 1, 3fmt.Println(a, b, c)if 7%2 == 0 {fmt.Println("7 is even")} else {fmt.Println("7 is odd")}t := 2 //声明并初始化一个新的变量switch t {case 0, 1:fmt.Println("zero or one")case 2:fmt.Println("two")default:fmt.Println("other")}tt := time.Now()switch {case tt.Hour() < 12:fmt.Println("it is before noon")default:fmt.Println("it is after noon")}v := 42switch v {case 100:fmt.Println(100)fallthroughcase 42:fmt.Println(42)fallthroughcase 1:fmt.Println(1)fallthroughdefault:fmt.Println("default")}for j := 7; j < 9; j++ {fmt.Println(j)}i := 1for i <= 3 {fmt.Println(i)i = i + 1}nums := []int{2, 3, 4}sum := 0for idx, num := range nums {fmt.Println("range to index", idx)sum += num}fmt.Println("sum:", sum)//遍历map, 得到 键 k 值 vm := make(map[string]int)m["hello"] = 0m["world"] = 1//if key and value both neededfor k, v := range m {fmt.Printf("%v %v\n", k, v)}//or only need keyfor k := range m {fmt.Printf("%v \n", k)}var aa [5]intfor i := 0; i < 3; i++ {aa[i] = ifmt.Println(aa[i])}bb := [5]int{1, 2, 3, 4, 5}fmt.Println(bb[4])var twoD [2][3]intfmt.Println(twoD[1][2])//切片s := make([]string, 3, 10)s[0] = "a"s[1] = "b"s[2] = "c"for i := 0; i < 3; i++ {fmt.Println(s[i])}//映射mm := map[string]int{"one": 111, "two": 2}fmt.Println(len(mm), mm["one"], mm["wtf"])fmt.Println(add(10, 2))n := 5add2(n)        //not workingfmt.Println(n) // 5add2ptr(&n)    //workingfmt.Println(n) // 7//初始化结构体cc := user{name: "wang", password: "1024"}fmt.Printf("%+v\n", cc) //{name:wang password:1024}fmt.Println(cc.name)fmt.Println(cc.password)//调用密码匹配结构体函数var dd userdd.resetPassword("2048")fmt.Println(dd.checkPassword("2048")) //true//调用错误函数u, err := findUser([]user{{"wang", "1024"}}, "wang")if err != nil {fmt.Println(err)return}fmt.Println(u.name)if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {fmt.Println(err) //not foundreturn} else {fmt.Println(u.name)}
}

🔑小项目实战

🐘猜数字游戏

描述

猜数字,猜大猜小了,都会有提示,知道最终猜中,结束循环

如果输入不合法,字符串不能转化为整型,就会提示Invalid Input

代码

// 数字猜测游戏
package mainimport ( //导入第3方包"bufio""fmt"_ "fmt" //format包, 输入输出字符串"math/rand"_ "math/rand""os""strconv"_ "strconv""strings""time"_ "time"
)func main() {maxNum := 100//Goland 1.15后不需要随机数种子, 会自动调用math/rand包的函数rand.Seed(time.Now().UnixNano())secretNumber := rand.Intn(maxNum) //生成0~100随机数//fmt.Println("The secret number is ", secretNumber)fmt.Println("Please input your guess")reader := bufio.NewReader(os.Stdin) //os.Stdin得到Stdin文件, bufio.NewReader转成只读的流for {input, err := reader.ReadString('\n') //ReadString读入一行输入if err != nil {fmt.Println("An error occured while reading input. Please try again", err)continue}input = strings.TrimSuffix(input, "\r\n") //strings包的TrimSuffix函数去掉回车符和换行符guess, err := strconv.Atoi(input) //Atoi转数字if err != nil {fmt.Println("Invalid input. Please enter an integer value")continue}fmt.Println("Your 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}}
}

cmd测试

🐘在线词典

描述

先说下几个代码生成的工具(网址)👇
(1)👇Convert curl commands to Go (curlconverter.com)

用于将 cURL 命令转换为 Go 代码(也可以是其他语言)

cURL 是一个常用的命令行工具,用于发送 HTTP 请求并获取响应

将 cURL 命令转换为相应的编程语言代码,可以方便地在代码中,执行相同的 HTTP 请求

(2)👇JSON转Golang Struct - 在线工具 - OKTools

这个更好用,支持20多种转换

彩云小译 - 在线翻译 (caiyunapp.com)

👆上面网址打开,开发者工具

右键name,Copy,Copy as Curl(bash)粘贴到下面网址👇 就转化成Go代码了(或者其他语言)

Convert curl commands to code

(1)用Go语言发送http请求,解析json

代码1  --  抓包

输出一长串 json 字符

package mainimport ("fmt""io""log""net/http""strings"
)func main() {client := &http.Client{}//字符串data转成流var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)//1.创建请求//创建http的POST请求, 第二个参数是urlreq, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)if err != nil {log.Fatal(err)}//2.设置请求头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", "6febce1e00ffc1f9e33ddd0354386064")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="115", "Chromium";v="115"`)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/115.0.0.0 Safari/537.36 Edg/115.0.1901.183")req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")//3.发起请求resp, err := client.Do(req)if err != nil {log.Fatal(err) //请求失败,退出进程}defer resp.Body.Close() //拿到请求后,通过defer关闭流bodyText, err := io.ReadAll(resp.Body)if err != nil {log.Fatal(err)}fmt.Printf("%s\n", bodyText) //打印json字符串
}

👇由于最终要通过变量输入,而不是 json 字符串输入,所以需要 json 实例化

代码2  --  生成request body 

实例化一个 json,需要构造一个结构体,使结构体的名字和 json 的结构一一对应,再调用

json.Marshal()函数,举例👇

package mainimport ("encoding/json""fmt"
)type userInfo struct {Name stringAge intHobby []string
}func main() {a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}buf, err := json.Marshal(a)//...buf, err = json.MarshalIndent(a, "", "\t")...
}

修改后的代码

package mainimport ("bytes""encoding/json""fmt""io""log""net/http"
)// 构造结构体
type DictRequest struct {TransType string `json:"trans_type"` //翻译Source    string `json:"source"`     //原文本UserID    string `json:"user_id"`    //用户ID
}func main() {client := &http.Client{}//new一个结构体变量并初始化字段名request := DictRequest{TransType: "en2zh", Source: "good"}buf, err := json.Marshal(request) //json.Marshal实例化request//request转bytes数组var data = bytes.NewReader(buf)//1.创建请求//创建http的POST请求, 第二个参数是urlreq, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)if err != nil {log.Fatal(err)}//2.设置请求头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", "6febce1e00ffc1f9e33ddd0354386064")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="115", "Chromium";v="115"`)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/115.0.0.0 Safari/537.36 Edg/115.0.1901.183")req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")//3.发起请求resp, err := client.Do(req)if err != nil {log.Fatal(err) //请求失败,退出进程}defer resp.Body.Close() //拿到请求后,通过defer关闭流bodyText, err := io.ReadAll(resp.Body)if err != nil {log.Fatal(err)}fmt.Printf("%s\n", bodyText) //打印json字符串
}

代码3  --  解析 response body

将一大串 response 解析,获取里面的几个字段

按 request 的方式,构造结构体,结构体字段和返回的 response 一一对应,再将返回的 json 字符串反序列化到结构体里


但是,这里的字段非常复杂👆,这时需要一个 json 转Go Struct 的工具👇

JSON转Golang Struct - 在线工具 - OKTools

整块代码粘贴过去

右键copy value,转换-嵌套

type DictResponse struct {Rc   int `json:"rc"`Wiki struct {} `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"`
}

代码4  --  打印结果

var dictResponse DictResponse //定义DictResponse变量//json.Unmarshal将bodyText解析为结构体变量的值err = json.Unmarshal(bodyText, &dictResponse) //& 写入结构体if err != nil {log.Fatal(err)}fmt.Printf("%#v\n", dictResponse) //%#v 打印结构体 详细值

输出

但是我们只需要 音标(prons) 和 解释(explanations)

代码5  --  完善结果

代码6  --  完整代码

package mainimport ("bytes""encoding/json""fmt""io""log""net/http""os"
)// 构造结构体
type DictRequest struct {TransType string `json:"trans_type"` //翻译Source    string `json:"source"`     //原文本UserID    string `json:"user_id"`    //用户ID
}// 结构体嵌套
type DictResponse struct {Rc   int `json:"rc"`Wiki struct {} `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 query(word string) {client := &http.Client{}//new一个结构体变量并初始化字段名//request := DictRequest{TransType: "en2zh", Source: "good"} //固定字符串request := DictRequest{TransType: "en2zh", Source: word} //变量wordbuf, err := json.Marshal(request)                        //json.Marshal实例化request//request转bytes数组var data = bytes.NewReader(buf)//1.创建请求//创建http的POST请求, 第二个参数是urlreq, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)if err != nil {log.Fatal(err)}//2.设置请求头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", "6febce1e00ffc1f9e33ddd0354386064")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="115", "Chromium";v="115"`)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/115.0.0.0 Safari/537.36 Edg/115.0.1901.183")req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")//3.发起请求resp, err := client.Do(req)if err != nil {log.Fatal(err) //请求失败,退出进程}defer resp.Body.Close() //拿到请求后,通过defer关闭流bodyText, err := io.ReadAll(resp.Body)if err != nil {log.Fatal(err)}if resp.StatusCode != 200 { //记录错误信息并终止执行, 便于排查问题log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))}var dictResponse DictResponse //定义DictResponse变量//json.Unmarshal将bodyText解析为结构体变量的值err = json.Unmarshal(bodyText, &dictResponse) //& 写入结构体if err != nil {log.Fatal(err)}fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)for _, item := range dictResponse.Dictionary.Explanations {fmt.Println(item) //range遍历数组每个元素并打印}
}func main() {if len(os.Args) != 2 { //后面没有接一个单词,打印错误并退出fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello`)os.Exit(1)}word := os.Args[1] //后面接一个单词,打印单词query(word)
}

cmd测试

🐘Socks5代理服务器

🔑介绍

📚原理

SOCKS5代理服务器充当客户端和目标服务器之间的中介。它接收来自客户端的请求,并将其转发到目标服务器,然后将目标服务器的响应转发回客户端。这样,客户端可以通过代理服务器访问目标服务器上的资源,同时实现了客户端与目标服务器之间的隔离和隐藏👇

👆

  1. 客户端连接到SOCKS5代理服务器:客户端首先与SOCKS5代理服务器建立连接。这个连接是直接建立的,不会经过目标服务器

  2. 客户端发送代理请求:一旦与代理服务器建立连接,客户端就会向代理服务器发送代理请求。请求中包含要连接的目标服务器的地址、端口号和认证信息(如果需要)

  3. 代理服务器建立连接:代理服务器收到代理请求后,会解析其中的目标服务器地址和端口号,并尝试与目标服务器建立连接

  4. 代理服务器与目标服务器交换数据:一旦代理服务器成功地与目标服务器建立连接,它会在客户端和目标服务器之间进行数据中转。代理服务器接收来自客户端的数据,并将其发送给目标服务器;相应地,它从目标服务器接收数据,并将其发送回客户端

  5. 数据传输完成:当数据传输完成后,可以根据具体的需求来决定是否保持连接或断开连接

💻TCP echo server

Socks5代理服务器较为复杂,我们先从简化版本 TCP echo server开始

TCP回显服务器(TCP echo server)是一种基于TCP协议的网络服务器,它接收客户端发送的数据并将其原封不动地返回给客户端

不挣扎了,检索了2小时,都没跑通,最后群里一问,这玩意没法在Windows跑?!

所以,下面👇只是粘贴代码上去,不作解释和运行测试

package mainimport ("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}}
}

🚢auth

...

package mainimport ("bufio""fmt""io""log""net"
)const socks5Ver = 0x05
const cmdBind = 0x01
const atypeIPV4 = 0x01
const atypeHOST = 0x03
const atypeIPV6 = 0x04func 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)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 | NMETHODS | METHODS  |// +----+----------+----------+// | 1  |    1     | 1 to 255 |// +----+----------+----------+// VER: 协议版本,socks5为0x05// NMETHODS: 支持认证的方法数量// METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:// X’00’ NO AUTHENTICATION REQUIRED// X’02’ USERNAME/PASSWORDver, err := reader.ReadByte()if err != nil {return fmt.Errorf("read ver failed:%w", err)}if ver != socks5Ver {return fmt.Errorf("not supported ver:%v", 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)// +----+--------+// |VER | METHOD |// +----+--------+// | 1  |   1    |// +----+--------+_, err = conn.Write([]byte{socks5Ver, 0x00})if err != nil {return fmt.Errorf("write failed:%w", err)}return nil
}

🏘请求阶段

...

package mainimport ("bufio""encoding/binary""errors""fmt""io""log""net"
)const socks5Ver = 0x05
const cmdBind = 0x01
const atypeIPV4 = 0x01
const atypeHOST = 0x03
const atypeIPV6 = 0x04func 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)err := auth(reader, conn)if err != nil {log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)return}err = connect(reader, conn)if err != nil {log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)return}
}func auth(reader *bufio.Reader, conn net.Conn) (err error) {// +----+----------+----------+// |VER | NMETHODS | METHODS  |// +----+----------+----------+// | 1  |    1     | 1 to 255 |// +----+----------+----------+// VER: 协议版本,socks5为0x05// NMETHODS: 支持认证的方法数量// METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:// X’00’ NO AUTHENTICATION REQUIRED// X’02’ USERNAME/PASSWORDver, err := reader.ReadByte()if err != nil {return fmt.Errorf("read ver failed:%w", err)}if ver != socks5Ver {return fmt.Errorf("not supported ver:%v", 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)}// +----+--------+// |VER | METHOD |// +----+--------+// | 1  |   1    |// +----+--------+_, err = conn.Write([]byte{socks5Ver, 0x00})if err != nil {return fmt.Errorf("write failed:%w", err)}return nil
}func connect(reader *bufio.Reader, conn net.Conn) (err error) {// +----+-----+-------+------+----------+----------+// |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |// +----+-----+-------+------+----------+----------+// | 1  |  1  | X'00' |  1   | Variable |    2     |// +----+-----+-------+------+----------+----------+// VER 版本号,socks5的值为0x05// CMD 0x01表示CONNECT请求// RSV 保留字段,值为0x00// ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。//   0x01表示IPv4地址,DST.ADDR为4个字节//   0x03表示域名,DST.ADDR是一个可变长度的域名// DST.ADDR 一个可变长度的值// DST.PORT 目标端口,固定2个字节buf := make([]byte, 4)_, err = io.ReadFull(reader, buf)if err != nil {return fmt.Errorf("read header failed:%w", err)}ver, cmd, atyp := buf[0], buf[1], buf[3]if ver != socks5Ver {return fmt.Errorf("not supported ver:%v", ver)}if cmd != cmdBind {return fmt.Errorf("not supported cmd:%v", cmd)}addr := ""switch atyp {case atypeIPV4:_, 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("read hostSize 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: no supported yet")default:return errors.New("invalid 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)// +----+-----+-------+------+----------+----------+// |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |// +----+-----+-------+------+----------+----------+// | 1  |  1  | X'00' |  1   | Variable |    2     |// +----+-----+-------+------+----------+----------+// VER socks版本,这里为0x05// REP Relay field,内容取值如下 X’00’ succeeded// RSV 保留字段// ATYPE 地址类型// BND.ADDR 服务绑定的地址// BND.PORT 服务绑定的端口DST.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
}

🤪relay阶段

...

package mainimport ("bufio""context""encoding/binary""errors""fmt""io""log""net"
)const socks5Ver = 0x05
const cmdBind = 0x01
const atypeIPV4 = 0x01
const atypeHOST = 0x03
const atypeIPV6 = 0x04func 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)err := auth(reader, conn)if err != nil {log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)return}err = connect(reader, conn)if err != nil {log.Printf("client %v auth failed:%v", conn.RemoteAddr(), err)return}
}func auth(reader *bufio.Reader, conn net.Conn) (err error) {// +----+----------+----------+// |VER | NMETHODS | METHODS  |// +----+----------+----------+// | 1  |    1     | 1 to 255 |// +----+----------+----------+// VER: 协议版本,socks5为0x05// NMETHODS: 支持认证的方法数量// METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:// X’00’ NO AUTHENTICATION REQUIRED// X’02’ USERNAME/PASSWORDver, err := reader.ReadByte()if err != nil {return fmt.Errorf("read ver failed:%w", err)}if ver != socks5Ver {return fmt.Errorf("not supported ver:%v", 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)}// +----+--------+// |VER | METHOD |// +----+--------+// | 1  |   1    |// +----+--------+_, err = conn.Write([]byte{socks5Ver, 0x00})if err != nil {return fmt.Errorf("write failed:%w", err)}return nil
}func connect(reader *bufio.Reader, conn net.Conn) (err error) {// +----+-----+-------+------+----------+----------+// |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |// +----+-----+-------+------+----------+----------+// | 1  |  1  | X'00' |  1   | Variable |    2     |// +----+-----+-------+------+----------+----------+// VER 版本号,socks5的值为0x05// CMD 0x01表示CONNECT请求// RSV 保留字段,值为0x00// ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。//   0x01表示IPv4地址,DST.ADDR为4个字节//   0x03表示域名,DST.ADDR是一个可变长度的域名// DST.ADDR 一个可变长度的值// DST.PORT 目标端口,固定2个字节buf := make([]byte, 4)_, err = io.ReadFull(reader, buf)if err != nil {return fmt.Errorf("read header failed:%w", err)}ver, cmd, atyp := buf[0], buf[1], buf[3]if ver != socks5Ver {return fmt.Errorf("not supported ver:%v", ver)}if cmd != cmdBind {return fmt.Errorf("not supported cmd:%v", cmd)}addr := ""switch atyp {case atypeIPV4:_, 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("read hostSize 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: no supported yet")default:return errors.New("invalid 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)// +----+-----+-------+------+----------+----------+// |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |// +----+-----+-------+------+----------+----------+// | 1  |  1  | X'00' |  1   | Variable |    2     |// +----+-----+-------+------+----------+----------+// VER socks版本,这里为0x05// REP Relay field,内容取值如下 X’00’ succeeded// RSV 保留字段// ATYPE 地址类型// BND.ADDR 服务绑定的地址// BND.PORT 服务绑定的端口DST.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)cancel()}()<-ctx.Done()return nil
}

 📚Hertz框架

资源

看一遍👇

一文学会 Go 的三个主流开发框架| 青训营笔记 - HikariLan's Blog (minecraft.kim)

李文周的👇

【置顶】Go语言学习之路/Go语言教程 | 李文周的博客 (liwenzhou.com)

Hertz中文教程👇

Hertz | CloudWeGo

Hertz(Github搭建安装学习全流程)👇

hertz/README_cn.md at develop · cloudwego/hertz (github.com)

http://www.15wanjia.com/news/35252.html

相关文章:

  • 成都设计公司怎么选新乡seo推广
  • 淄博知名的做网站推广怎么推广平台
  • 怀柔青岛网站建设网页设计素材
  • 做窗帘什么网站天津疫情最新情况
  • w微信网站开发网络营销的发展前景
  • 一个新的网站开发语言百度指数使用方法
  • wordpress nova 汉化淘宝seo是什么意思
  • 优秀的网站有哪些内容市场营销实务
  • 上海易雅达网站建设公司怎么样百度竞价广告点击器
  • 电子商务网站建设商城网站企业推广的渠道有哪些
  • 苏州网站定制公司什么平台可以做引流推广
  • 深圳做微商网站制作google seo教程
  • 网站流量一直下降网络优化师是什么工作
  • 上海网站制作公司的排名上海培训机构整顿
  • 群晖 做网站 Java宁波seo链接优化
  • 政府网站建设的基本原则厦门网站seo哪家好
  • 网站开发维护面试免费二级域名建站
  • free wordpress themes宁波谷歌seo推广公司
  • 做网站需要缴什么费用新版阿里指数官网
  • wordpress+粘贴表格优化营商环境个人心得体会
  • 如何选择丹阳网站建设教师遭网课入侵直播录屏曝光广场舞
  • 黄江镇仿做网站百度seo关键词优化排名
  • 网站建设是什么行业个人怎么做网站
  • 优秀的网页设计网站搜狗关键词优化软件
  • 网站底部加编码世界十大网站排名
  • 创建网站运营费用网络广告策划与制作
  • asp.netweb网站开发北京网站优化效果
  • 网站建设的认识百度免费下载安装百度
  • 做网站编辑的感受海南百度总代理
  • 黄聪 wordpress谷歌seo外链平台