go|青训营笔记
这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天
一,本堂课重点内容
生成随机数
输入
循环
socks5
TCP echo server
recover (捕获异常)
二、详细知识点介绍:
expected 'package', found 'EOF'(ctrl+s 保存一下)
生成随机数
maxnumber := 100
rand.Seed(time.Now().UnixNano())
secretNumber := rand.Intn(maxnumber)
输入
reader:=bufio.NewReader(os.Stdin) //只读流
input,err:=reader.ReadString('\n'//读取一行) \\从只读流中读取
input =strings.TrimSuffix(input,"\n") \\去除input中的\n
循环
for{}
将[curl]命令转换为Python,JavaScript,PHP,R,Go,C#,Ruby,Rust,Elixir,Java,MATLAB,Dart,CFML,Ansible URI或JSONhttps://curlconverter.com/
将网页中的json(需要网页中的network->resoons)转换为相应的结构体形式oktools.net/
request :=DictRequest(前面声明的结构体){transtype: "en2zh",Source: "good"}
buf,err:=json.Marshal(request)对相应结构进行编码
var data = bytes.NewReader(buf)NewReader创建一个从buf读取数据的byte类型Reader
err = json.Unmarshal(bodyText, &dictResponse)反序列化
Json Marshal:将数据编码成json字符串
Json Unmarshal:将json字符串解码到相应的数据结构
结构体中json:"trans_type"等命名首字母用大写
socks5
TCP echo server
panic (抛出异常)
停止当前函数执行 一直向上返回,执行每一层的defer 如果没有遇见recover, 程序退出
recover (捕获异常)
仅在defer调用中使用 获取panic的值 如果无法处理,可重新panic
实践练习例子:
package main
import (
"bufio"
"log"
"net"
)
func main() {
sever, err := net.Listen("tcp", "127.0.0.1:1080")
if err != nil {
panic(err)
}
for {
client, err := sever.Accept() //Accept等待并将下一个连接返回给侦听器
if err != nil {
log.Printf("Accpet failed %v", err) //Printf调用Output以打印到标准记录器。参数以fmt.Printf的方式处理
continue
}
go process(client)
}
}
func process(coon net.Conn) {
defer coon.Close()
reader := bufio.NewReader(coon)
for {
b, err := reader.ReadByte()
if err != nil {
break
}
_, err = coon.Write([]byte{b})
if err != nil {
break
}
}
}
+----+-----+-------+------+----------+----------+
// |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个字节
先写一个net类型(写network和adress)再用Accept等待并将下一个连接返回给侦听器建立TCR连接
再写一个方法并调用{ 用bufio.NewReader写入一个变量(例:记为reader)
**->**再通过Readbyte判断是否为socks5Ver以及method
**—>**Write([]byte{socks5Ver, 0x00})写回net.Coon
**-->**进入请求阶段 将reader写进数组填充VER CMD ATYP
**-->**根据ATYP分三类 进行处理
atypIPV4 = 0x01
_, 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])
atypeHOST = 0x03
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)
atypeIPV6 = 0x04
-->
将reader切片(两字节)获得服务绑定的端口DST.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
解释
(转载 www.cnblogs.com/sunlong88/p…)
encoding/binary包实现了简单的数字(固定长度的数字类型或者只包含定长值的结构体或数组)与字节系列的转换以及变长值的编解码。
func Write(w io.Writer, order ByteOrder, data interface{}) error 序列化,将数据转换成byte字节流,order指定字节序
func Read(r io.Reader, order ByteOrder, data interface{}) error 反序列化,将字节流转换成原始数据
order: binary.BigEndian(大端模式):内存的低地址存放着数据高位 binary.LittleEndian(小端模式):内存的低地址存放着数据地位
-->
net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port)) 用tcp协议将IP,端口等进行连接//
-->
这里需要用户浏览器与底层服务器进行双向转换
Copy单向转换
go func() {
_, _ = io.Copy(dest, reader)用户浏览器到底层服务器
cancel()
}()
go func() {
_, _ = io.Copy(conn, dest)底层服务器到用户浏览器
cancel()
}()
} 四、课后个人总结:
soscks5还需多加练习
五、引用参考:
www.cnblogs.com/sunlong88/p…) go-by-example/main.go at master · wangkechun/go-by-example (github.com)