课程源码:https://github.com/wangkechun/go-by-example/
短链接:https://hi-hi.cn/go
1 简介
1.1 什么是Go语言
- 高性能,高并发
- 语法简单,学习曲线平缓
- 丰富的标准库
- 完善的工具链
- 静态链接
- 快速编译
- 跨平台
- 垃圾回收
package main
import(
"net/http"
)
func main(){
http.Handle("/",http.FileServer(http.Dor(".")))
http.ListenAndServe(":8080",nil)
}
1.2 哪些公司在使用Go语言
1.3 字节跳动为什么全面拥抱Go语言
- 最初使用的Python,由于性能问题换成了Go
- C++不太适合在线Web业务
- 早期团队非Java背景
- 性能比较好
- 部署简单,学习成本低
- 内部 RPC和HTTP框架的推广
2 入门
2.1 开发环境
- 安装Golang
https://go.dev/
https://studygolang.com/dl
https://goproxy.cn/ - 配置集成开发环境
- 基于云的开发环境
https://gitpod.io/#github.com/wangkechun/go-by-example
短链接:https://hi-hi.cn/gitpod
2.2 基础语法和标准库
2.2.1 Hello World
package main
import (
"fmt"
)
func main() {
fmt.Println("hello world!")
}
运行结果:
2.2.2 变量
goland中常量没有确定的类型,它会根据使用的上下文自动确定类型
package main
import (
"fmt"
"math"
)
func main() {
var a = "initial"
var b, c int = 1, 2
var d = true
var e float64
f := float32(e)
g := a + "foo"
fmt.Println(a, b, c, d, e, f) //运行结果为:initial 1 2 true 0 0
fmt.Println(g) //运行结果为:initialfoo
const s string = "constant"
const h = 500000000
const i = 3e20 / h
fmt.Println(s, h, i, math.Sin(h)) //运行结果:constant 500000000 6e+11 -0.28470407323754404
}
2.2.3 if else
package main
import "fmt"
func main() {
if 7%2 == 0 {
fmt.Println("7 is even")
} else {
fmt.Println("7 is odd")
}
if 8%4 == 0 {
fmt.Println("8 is divisible by 4")
}
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
}
运行结果:
2.2.4 循环
package main
import "fmt"
func main() {
i := 1
for {
fmt.Println("loop")
break
}
for j := 7; j < 9; j++ {
fmt.Println(j)
}
for n := 0; n < 5; n++ {
if n%2 == 0 {
continue
}
fmt.Println(n)
}
for i <= 3 {
fmt.Println(i)
i = i + 1
}
}
运行结果:
2.2.5 switch
package main
import (
"fmt"
"time"
)
func main() {
a := 2
switch a {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
case 4, 5:
fmt.Println("four or five")
default:
fmt.Println("other")
}
t := time.Now()
switch {
case t.Hour() < 12:
fmt.Println("its before noon")
default:
fmt.Println("its after noon")
}
}
运行结果:
2.2.6 数组
package main
import "fmt"
func main() {
var a [5]int
a[4] = 100
fmt.Println(a[4], len(a)) //输出为:100 5
b := [5]int{1, 2, 3, 4, 5}
fmt.Println(b) //输出为:[1 2 3 4 5]
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
fmt.Println("2d: ", twoD) //输出为:2d: [[0 1 2] [1 2 3]]
}
2.2.7 切片
package main
import "fmt"
func main() {
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
fmt.Println(m) //输出为:map[one:1 two:2]
fmt.Println(len(m)) //输出为:2
fmt.Println(m["one"]) //输出为:1
fmt.Println(m["unknow"]) //输出为:0
r, ok := m["unknow"]
fmt.Println(r, ok) //输出为:0 false
delete(m, "one")
m2 := map[string]int{"one": 1, "two": 2}
var m3 = map[string]int{"one": 1, "two": 2}
fmt.Println(m2, m3) //输出为:map[one:1 two:2] map[one:1 two:2]
}
2.2.8 range
package main
import "fmt"
func main() {
nums := []int{2, 3, 4}
sum := 0
for i, num := range nums {
sum += num
if num == 2 {
fmt.Println("index:", i, "num:", num) //输出为:index: 0 num: 2
}
}
fmt.Println(sum) //输出为:9
m := map[string]string{"a": "A", "b": "B"}
for k, v := range m {
fmt.Println(k, v) //输出为:a A b B
}
for k := range m {
fmt.Println("key", k) //输出为:key a key b
}
}
2.2.9 函数
package main
import "fmt"
func add(a int, b int) int {
return a + b
}
func add2(a, b int) int {
return a + b
}
//ok 表示是否存在
func exists(m map[string]string, k string) (v string, ok bool) {
v, ok = m[k]
return v, ok
}
func main() {
res := add(1, 2)
fmt.Println(res) //输出为:3
v, ok := exists(map[string]string{"a": "A"}, "a")
fmt.Println(v, ok) //输出为:A true
}
2.2.10 指针
package main
import "fmt"
//此方法无效
func add2(n int) {
n += 2
}
func add2ptr(n *int) {
*n += 2
}
func main() {
n := 5
add2(n)
fmt.Println(n) //运行结果:5
add2ptr(&n)
fmt.Println(n) //运行结果:7
}
2.2.11 结构体
package main
import "fmt"
type user struct {
name string
password string
}
func main() {
a := user{name: "wang", password: "1024"}
b := user{"wang", "1024"}
c := user{name: "wang"}
c.password = "1024"
var d user
d.name = "wang"
d.password = "1024"
fmt.Println(a, b, c, d) //输出为:{wang 1024} {wang 1024} {wang 1024} {wang 1024}
fmt.Println(checkPassword(a, "haha")) //输出为:false
fmt.Println(checkPassword2(&a, "haha")) //输出为:false
}
func checkPassword(u user, password string) bool {
return u.password == password
}
func checkPassword2(u *user, password string) bool {
return u.password == password
}
2.2.12 结构体方法
package main
import "fmt"
type user struct {
name string
password string
}
func (u user) checkPassword(password string) bool {
return u.password == password
}
func (u *user) resetPassword(password string) {
u.password = password
}
func main() {
a := user{name: "wang", password: "1024"}
a.resetPassword("2048")
fmt.Println(a.checkPassword("2048")) //输出为:true
}
2.2.13 错误处理
package main
import (
"errors"
"fmt"
)
type user struct {
name string
password string
}
//函数中加一个err 表示函数会返回错误
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 main() {
u, err := findUser([]user{{"wang", "1024"}}, "wang")
//必须先判断err是否为空
if err != nil {
fmt.Println(err)
return
}
fmt.Println(u.name) //输出为:wang
//另一种写法
if u, err := findUser([]user{{"wang", "1024"}}, "li"); err != nil {
fmt.Println(err) //输出为: not found
return
} else {
fmt.Println(u.name)
}
}
2.2.14 字符串操作
package main
import (
"fmt"
"strings"
)
func main() {
a := "hello"
//是否包含一个字符串
fmt.Println(strings.Contains(a, "ll")) //输出为:true
//字符串计数
fmt.Println(strings.Count(a, "l")) //输出为:2
//是否以某个字符串开头
fmt.Println(strings.HasPrefix(a, "he")) //输出为:true
//是否以某个字符串结尾
fmt.Println(strings.HasSuffix(a, "llo")) //输出为:true
//查找某个字符串的位置
fmt.Println(strings.Index(a, "ll")) //输出为:2
//连接多个字符串
fmt.Println(strings.Join([]string{"he", "llo"}, "-")) //输出为:he-llo
//重复多个字符串
fmt.Println(strings.Repeat(a, 2)) //输出为:hellohello
//替换字符串
fmt.Println(strings.Replace(a, "e", "E", -1)) //输出为:hEllo
//将分隔符去除
fmt.Println(strings.Split("a-b-c", "-")) //输出为:[a b c]
//全部变为小写字母
fmt.Println(strings.ToLower(a)) //输出为:hello
//全部变为大写字母
fmt.Println(strings.ToUpper(a)) //输出为:HELLO
fmt.Println(len(a)) //输出为:5
b := "你好"
fmt.Println(len(b)) //输出为:6
}
2.2.15 字符串格式化
package main
import "fmt"
type point struct {
x, y int
}
func main() {
s := "hello"
n := 123
p := point{1, 2}
fmt.Println(s, n) //输出为:hello 123
fmt.Println(p) //输出为:{1 2}
fmt.Printf("s=%v\n", s) //输出为:s=hello
fmt.Printf("n=%v\n", n) //输出为:n=123
fmt.Printf("p=%v\n", p) //输出为:p={1 2}
//打印的详细,将字段名打印出来
fmt.Printf("p=%+v\n", p) //输出为:p={x:1 y:2}
//将整个结构体的类型名称,字段名打印出来
fmt.Printf("p=%#v\n", p) //输出为:p=main.point{x:1, y:2}
f := 3.141592653
fmt.Println(f) //输出为:3.141592653
fmt.Printf("%.2f\n", f) //输出为:3.14
}
2.2.16 JSON处理
package main
import (
"encoding/json"
"fmt"
)
type userInfo struct {
Name string
Age int `json:"age"`
Hobby []string
}
func main() {
a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}}
//使用json.Marshal将a序列化
buf, err := json.Marshal(a)
if err != nil {
panic(err)
}
fmt.Println(buf)
fmt.Println(string(buf))
//json.MarshalIndent:按照indent格式化输出
buf, err = json.MarshalIndent(a, "", "\t")
if err != nil {
panic(err)
}
fmt.Println(string(buf))
var b userInfo
//json.Unmarshal:将序列化的数据反序列化到一个空的变量中
err = json.Unmarshal(buf, &b)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", b)
}
运行结果:
2.2.17 时间处理
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now) //输出为:2022-05-09 15:23:49.6706407 +0800 CST m=+0.001026201
t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC)
t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC)
fmt.Println(t) //输出为:2022-03-27 01:25:36 +0000 UTC
fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) //输出为:2022 March 27 1 25
fmt.Println(t.Format("2006-01-02 15:04:05")) //输出为:2022-03-27 01:25:36
//两个时间段进行减法
diff := t2.Sub(t)
fmt.Println(diff) //输出为:1h5m0s
fmt.Println(diff.Minutes(), diff.Seconds()) //输出为:65 3900
//Parse()函数用于解析格式化的字符串,然后查找它形成的时间值
t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-07 01:25:36")
if err != nil {
panic(err)
}
fmt.Println(t3 == t) //输出为:false
//now.Unix()获取时间戳
fmt.Println(now.Unix()) //输出为:1652081029
}
2.2.18 数字解析
字符串和数字的转换
package main
import (
"fmt"
"strconv"
)
func main() {
f, _ := strconv.ParseFloat("1.234", 64)
fmt.Println(f) //输出为:1.234
//10进制 返回的是64位精度的整数
n, _ := strconv.ParseInt("111", 10, 64)
fmt.Println(n) //输出为:111
n1, _ := strconv.ParseInt("0x1000", 0, 64)
fmt.Println(n1) //输出为:4096
n2, _ := strconv.Atoi("123")
fmt.Println(n2) //输出为:4096
n3, err := strconv.Atoi("AAA")
fmt.Println(n3, err) //输出为:0 strconv.Atoi: parsing "AAA": invalid syntax
}
2.2.19 进程信息
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
//进程在执行时候的一些命令和参数
fmt.Println(os.Args)
//获取环境变量
fmt.Println(os.Getenv("PATH"))
//写入环境变量
fmt.Println(os.Setenv("AA", "BB"))
//快速启动子进程,获取其输入输出
buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput()
if err != nil {
panic(err)
}
fmt.Println(string(buf))
}
3 实战
3.1 猜谜游戏
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
//设置一个随机数
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
fmt.Println("The secret mumber 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
}
//去掉换行符
input = strings.TrimSuffix(input, "\n")
//input = strings.TrimSuffix(input, "\r")
//转换成数字
guess, err := strconv.Atoi(input)
if err != nil {
fmt.Println("Invalid input.Please enter an integer value",err)
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
}
}
}
运行结果:
使用 fmt.Scanf 来简化代码实现:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
//设置一个随机数
maxNum := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxNum)
fmt.Println("The secret mumber is ", secretNumber)
for {
fmt.Println("Please input your number: ")
//获取输入
var count int
fmt.Scanf("%d", &count)
fmt.Println("You guess is", count)
if count > secretNumber{
fmt.Println("your guess is bigger than the secret number. Please try again")
}else if count < secretNumber{
fmt.Println("your guess is smaller than the secret number. Please try again")
}else{
fmt.Println("correct,you legend")
break
}
}
}
3.2 命令行词典
- 抓包
彩云小译 :https://fanyi.caiyunapp.com/ - 代码生成
将curl命令转为Go:https://curlconverter.com/#go - 生成request body
- 解析response body
JSON转Golang Struct:https://oktools.net/json2go - 打印结果
- 完善代码
在彩云小译上:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type DictResponse 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"`
}
type DictRequest struct{
TransType string `json:"trans_type"`
Source string `json:"source"`
UserID string `json:"user_id"`
}
func query(word string) {
client := &http.Client{}
//var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
//request := DictRequest{TransType: "en2zh",Source: "good"}
request := DictRequest{TransType: "en2zh",Source: word}
buf,err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewBuffer(buf)
//创建请求
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
//设置请求头
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
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/100.0.4896.127 Safari/537.36")
req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
req.Header.Set("app-name", "xy")
req.Header.Set("os-type", "web")
req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"`)
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("sec-ch-ua-platform", `"Windows"`)
//发起请求
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)
}
if resp.StatusCode != 200 {
log.Fatal("bod StatusCode:",resp.StatusCode,"body",string(bodyText))
}
//fmt.Printf("%s\n", bodyText)
var dictResponse DictResponse
err = json.Unmarshal(bodyText,&dictResponse)
if err != nil {
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)
}
}
func main(){
//if len(os.Args) != 2{
// fmt.Fprintf(os.Stderr,`usage:simpleDict WORD example:simpleDict hello`)
// os.Exit(1)
//}
word := "study"
query(word)
}
运行结果:
换成火山翻译:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type DictRequest_huoshan struct{
Text string`json:"text"`
Language string `json:"language"`
}
type DictResponse_huoshan struct {
Words []struct {
Source int `json:"source"`
Text string `json:"text"`
PosList []struct {
Type int `json:"type"`
Phonetics []struct {
Type int `json:"type"`
Text string `json:"text"`
} `json:"phonetics"`
Explanations []struct {
Text string `json:"text"`
Examples []struct {
Type int `json:"type"`
Sentences []struct {
Text string `json:"text"`
TransText string `json:"trans_text"`
} `json:"sentences"`
} `json:"examples"`
Synonyms []interface{} `json:"synonyms"`
} `json:"explanations"`
Relevancys []interface{} `json:"relevancys"`
} `json:"pos_list"`
} `json:"words"`
Phrases []interface{} `json:"phrases"`
BaseResp struct {
StatusCode int `json:"status_code"`
StatusMessage string `json:"status_message"`
} `json:"base_resp"`
}
func query_huoshan(word string) {
client := &http.Client{}
//var data = strings.NewReader(`{"text":"good\n\n\n\n","language":"en"}`)
request := DictRequest_huoshan{Text: word,Language: "en"}
buf,err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewBuffer(buf)
req, err := http.NewRequest("POST", "https://translate.volcengine.com/web/dict/match/v1/?msToken=&X-Bogus=DFSzswVLQDcxI/5eSWCfZe9WX7rO&_signature=_02B4Z6wo00001yJiofgAAIDDomBbucDo8ysiYqVAAKru0cXDAbBoE-KWOV4RH4C2aGbXqF6VyKkuAlg88RPMWAF0u4SfdJLSBKPcaqDJFC3nUa1fTmHLL9zziNhAy0Mfz2so9Z5c2gFFpZ9gec", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("authority", "translate.volcengine.com")
req.Header.Set("accept", "application/json, text/plain, */*")
req.Header.Set("accept-language", "zh-CN,zh;q=0.9")
req.Header.Set("content-type", "application/json")
req.Header.Set("cookie", "x-jupiter-uuid=16522388961382340; i18next=zh-CN; s_v_web_id=verify_f65798b1ef5fb225931a8abb23bfee94; _tea_utm_cache_2018=undefined; ttcid=777643f23e7945069ab8946fd6a19f9c36; tt_scid=RhMZ-Kl5n0RzvNN0.c5vnhxMdlLjWm8Rrd6qz0LL9d-qL8wx6COhFnA0oeQBKFIebb37")
req.Header.Set("origin", "https://translate.volcengine.com")
req.Header.Set("referer", "https://translate.volcengine.com/translate?category=&home_language=zh&source_language=detect&target_language=zh&text=good%0A%0A%0A%0A")
req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"`)
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", "same-origin")
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36")
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)
if resp.StatusCode != 200 {
log.Fatal("bod StatusCode:",resp.StatusCode,"body",string(bodyText))
}
//fmt.Printf("%s\n", bodyText)
var dictResponse DictResponse_huoshan
err = json.Unmarshal(bodyText,&dictResponse)
if err != nil {
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)
//}
for _,word := range dictResponse.Words{
for _,polist := range word.PosList{
for _, explanation := range polist.Explanations {
fmt.Println(explanation.Text)
}
}
}
}
func main(){
//if len(os.Args) != 2{
// fmt.Fprintf(os.Stderr,`usage:simpleDict WORD example:simpleDict hello`)
// os.Exit(1)
//}
word := "good"
query_huoshan(word)
}
运行结果:
实现并行请求两个翻译引擎来提高响应速度:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"sync"
)
type DictRequest_huoshan struct{
Text string`json:"text"`
Language string `json:"language"`
}
type DictRequest_caiyun struct{
TransType string `json:"trans_type"`
Source string `json:"source"`
UserID string `json:"user_id"`
}
type DictResponse_huoshan struct {
Words []struct {
Source int `json:"source"`
Text string `json:"text"`
PosList []struct {
Type int `json:"type"`
Phonetics []struct {
Type int `json:"type"`
Text string `json:"text"`
} `json:"phonetics"`
Explanations []struct {
Text string `json:"text"`
Examples []struct {
Type int `json:"type"`
Sentences []struct {
Text string `json:"text"`
TransText string `json:"trans_text"`
} `json:"sentences"`
} `json:"examples"`
Synonyms []interface{} `json:"synonyms"`
} `json:"explanations"`
Relevancys []interface{} `json:"relevancys"`
} `json:"pos_list"`
} `json:"words"`
Phrases []interface{} `json:"phrases"`
BaseResp struct {
StatusCode int `json:"status_code"`
StatusMessage string `json:"status_message"`
} `json:"base_resp"`
}
type DictResponse_caiyun 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 query_huoshan(word string,wg *sync.WaitGroup) {
defer wg.Done() //当执行完函数,调用 把wg的等待组-1
client := &http.Client{}
//var data = strings.NewReader(`{"text":"good\n\n\n\n","language":"en"}`)
request := DictRequest_huoshan{Text: word,Language: "en"}
buf,err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewBuffer(buf)
req, err := http.NewRequest("POST", "https://translate.volcengine.com/web/dict/match/v1/?msToken=&X-Bogus=DFSzswVLQDcxI/5eSWCfZe9WX7rO&_signature=_02B4Z6wo00001yJiofgAAIDDomBbucDo8ysiYqVAAKru0cXDAbBoE-KWOV4RH4C2aGbXqF6VyKkuAlg88RPMWAF0u4SfdJLSBKPcaqDJFC3nUa1fTmHLL9zziNhAy0Mfz2so9Z5c2gFFpZ9gec", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("authority", "translate.volcengine.com")
req.Header.Set("accept", "application/json, text/plain, */*")
req.Header.Set("accept-language", "zh-CN,zh;q=0.9")
req.Header.Set("content-type", "application/json")
req.Header.Set("cookie", "x-jupiter-uuid=16522388961382340; i18next=zh-CN; s_v_web_id=verify_f65798b1ef5fb225931a8abb23bfee94; _tea_utm_cache_2018=undefined; ttcid=777643f23e7945069ab8946fd6a19f9c36; tt_scid=RhMZ-Kl5n0RzvNN0.c5vnhxMdlLjWm8Rrd6qz0LL9d-qL8wx6COhFnA0oeQBKFIebb37")
req.Header.Set("origin", "https://translate.volcengine.com")
req.Header.Set("referer", "https://translate.volcengine.com/translate?category=&home_language=zh&source_language=detect&target_language=zh&text=good%0A%0A%0A%0A")
req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"`)
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", "same-origin")
req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36")
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)
if resp.StatusCode != 200 {
log.Fatal("bod StatusCode:",resp.StatusCode,"body",string(bodyText))
}
//fmt.Printf("%s\n", bodyText)
var dictResponse DictResponse_huoshan
err = json.Unmarshal(bodyText,&dictResponse)
if err != nil {
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)
//}
for _,word := range dictResponse.Words{
for _,polist := range word.PosList{
for _, explanation := range polist.Explanations {
fmt.Println(explanation.Text)
}
}
}
}
func query_caiyun(word string,wg *sync.WaitGroup) {
defer wg.Done() //当执行完函数,调用 把wg的等待组-1
client := &http.Client{}
//var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
//request := DictRequest{TransType: "en2zh",Source: "good"}
request := DictRequest_caiyun{TransType: "en2zh",Source: word}
buf,err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewBuffer(buf)
//创建请求
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
//设置请求头
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
req.Header.Set("Origin", "https://fanyi.caiyunapp.com")
req.Header.Set("Referer", "https://fanyi.caiyunapp.com/")
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/100.0.4896.127 Safari/537.36")
req.Header.Set("X-Authorization", "token:qgemv4jr1y38jyq6vhvi")
req.Header.Set("app-name", "xy")
req.Header.Set("os-type", "web")
req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"`)
req.Header.Set("sec-ch-ua-mobile", "?0")
req.Header.Set("sec-ch-ua-platform", `"Windows"`)
//发起请求
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)
}
if resp.StatusCode != 200 {
log.Fatal("bod StatusCode:",resp.StatusCode,"body",string(bodyText))
}
//fmt.Printf("%s\n", bodyText)
var dictResponse DictResponse_caiyun
err = json.Unmarshal(bodyText,&dictResponse)
if err != nil {
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)
}
}
func main(){
fmt.Println(os.Args)
if len(os.Args) != 2{
fmt.Fprintf(os.Stderr,`usage:simpleDict WORD example:simpleDict hello`)
os.Exit(1)
}
//word := "good"
//query_huoshan(word)
word := os.Args[1]
wg := sync.WaitGroup{} //创建等待线程组
wg.Add(2) //等待组的计数器 +2
go query_huoshan(word,&wg) //调用线程,维护公共变量 wg
go query_caiyun(word,&wg) //调用线程,维护公共变量 wg
wg.Wait() //当等待组计数器不等于0时阻塞直到变0
}
运行结果:
3.3 SOCKS5代理
原理:
四个阶段:
- 协商/握手阶段
- 认证阶段【本示例不加密,没有此阶段】
- 请求阶段
- relay阶段
第一步:SOCKS5 代理 -TCP echo server
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
}
}
}
运行结果:
下载netcat,在对应文件下cmd
第二步:SOCKS5 代理-auth
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
)
const socks5Ver = 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")
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:支持认证的方法数量
//NMETHODS:对应NMETHODS,NMETHODS的值为多少,NMETHODS就有多少个字节,RFC预定义了一些值的含义,内容如下:
//X'00' NO AUTHENTICATION REQUIRED
//X'02' USERNAME/PASSWORD
ver,err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read ver failed:%w",err)
}
if ver != socks5Ver {
return fmt.Errorf("not supported ver:%v",err)
}
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
}
运行结果:
下载curl,在对应文件下cmd ,同时运行程序
在程序控制台中:
第三步:SOCKS5 代理 -请求阶段
package main
import (
"bufio"
"encoding/binary"
"errors"
"fmt"
"io"
"log"
"net"
)
const socks5Ver = 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")
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")
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:支持认证的方法数量
//NMETHODS:对应NMETHODS,NMETHODS的值为多少,NMETHODS就有多少个字节,RFC预定义了一些值的含义,内容如下:
//X'00' NO AUTHENTICATION REQUIRED
//X'02' USERNAME/PASSWORD
ver,err := reader.ReadByte()
if err != nil {
return fmt.Errorf("read ver failed:%w",err)
}
if ver != socks5Ver {
return fmt.Errorf("not supported ver:%v",err)
}
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
}
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",ver)
}
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("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 版本号,socks5的值为0x05
//REP Relay field,内容取值如下 X‘00’ succeeded
//RSV 保留字段
//ATYP 地址类型
//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
}
运行结果:
下载curl,在对应文件下cmd ,同时运行程序
如果将atypeIPV6代码改为atypeIPV4一样:
结果为:
第四步:SOCKS5 代理 -relay阶段
在上面的基础上添加下面代码: