xyxsw
文章35
标签3
分类0
go语言三个小项目 | 青训营笔记

go语言三个小项目 | 青训营笔记

猜数字

  1. 猜数字
    这个项目非常简单,它涉及到随机数的生成和用户输入操作。
    我们使用了bufio库来处理输入数据。
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')

简单字典

  1. 标准库strconv
    它主要用于字符和其他类型之间的转换。
strconv.Atoi(s string) int 
  1. 标准库strings
strings.TrimSuffix(s string ,  suffix string) string

删除末尾字符,如果没有就正常返回

  1. 网络库
client := &http.Client{}

初始化请求客户端

req,  err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict",  data)

构造头

req.Header.Set("authority",  "api.interpreter.caiyunai.com")

请求

bodyText,  err := io.ReadAll(resp.Body)
err = json.Unmarshal(bodyText,  &dictResponse)
  1. os库
word := os.Args[1]

获取环境参数

socks5代理

package main

import (
    "context"
    "encoding/binary"
    "fmt"
    "io"
    "net"
)

const (
    socks5Ver  = 0x05
    atypeIPV4  = 0x01
    atypeHOST  = 0x03
    cmdConnect = 0x01
)

func main() {
    // 假设在这里建立一个 net.Listener 监听 Socks5 代理请求

    for {
        client, err := acceptConnection()
        if err != nil {
            continue
        }

        // 开启一个 goroutine 处理客户端请求
        go handleSocks5Client(client)
    }
}

func acceptConnection() (net.Conn, error) {
    // 实现接收连接请求的逻辑
}

func handleSocks5Client(conn net.Conn) {
    defer conn.Close()

    // 鉴权阶段
    if err := auth(conn); err != nil {
        fmt.Println("Authentication error:", err)
        return
    }

    // 通讯阶段
    addr, err := connect(conn)
    if err != nil {
        fmt.Println("Connection error:", err)
        return
    }

    // 给客户端回包,表示连接成功
    _, _ = conn.Write([]byte{socks5Ver, 0x00, 0x00, atypeIPV4, 0, 0, 0, 0, 0, 0})

    // 开始进行数据转发
    dest, err := net.Dial("tcp", addr)
    if err != nil {
        fmt.Println("Failed to connect to destination:", err)
        return
    }
    defer dest.Close()

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()

    // 从客户端到目标地址的数据拷贝
    go func() {
        _, _ = io.Copy(dest, conn)
        cancel()
    }()

    // 从目标地址到客户端的数据拷贝
    go func() {
        _, _ = io.Copy(conn, dest)
        cancel()
    }()

    <-ctx.Done()
}

func auth(conn net.Conn) error {
    buf := make([]byte, 2)
    _, err := io.ReadFull(conn, buf)
    if err != nil {
        return err
    }

    ver, nmethods := buf[0], buf[1]
    methods := make([]byte, nmethods)
    _, err = io.ReadFull(conn, methods)
    if err != nil {
        return err
    }

    // 在这里根据收到的 methods 进行认证处理

    // 假设这里选择不需要认证,回包告知客户端不需要认证
    _, err = conn.Write([]byte{socks5Ver, 0x00})
    if err != nil {
        return err
    }

    return nil
}

func connect(conn net.Conn) (string, error) {
    buf := make([]byte, 4)
    _, err := io.ReadFull(conn, buf)
    if err != nil {
        return "", err
    }

    ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3]
    if ver != socks5Ver || cmd != cmdConnect {
        return "", fmt.Errorf("Unsupported SOCKS5 command")
    }

    var addr string
    switch atyp {
    case atypeIPV4:
        buf := make([]byte, 4)
        _, err := io.ReadFull(conn, buf)
        if err != nil {
            return "", err
        }
        addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])

    case atypeHOST:
        hostSizeBuf := make([]byte, 1)
        _, err := io.ReadFull(conn, hostSizeBuf)
        if err != nil {
            return "", err
        }
        hostSize := int(hostSizeBuf[0])
        hostBuf := make([]byte, hostSize)
        _, err = io.ReadFull(conn, hostBuf)
        if err != nil {
            return "", err
        }
        addr = string(hostBuf)
    }

    portBuf := make([]byte, 2)
    _, err = io.ReadFull(conn, portBuf)
    if err != nil {
        return "", err
    }
    port := binary.BigEndian.Uint16(portBuf)

    return fmt.Sprintf("%v:%v", addr, port), nil
}

使用 SOCKS5 代理的实现,涵盖了以下主要步骤:

鉴权阶段:

解析客户端发送的版本号、支持的认证方法数量和认证方法列表。
针对支持的认证方法进行验证,返回认证成功的回包。
通讯阶段:

解析客户端发送的连接请求,包括版本号、命令类型、目标地址类型、目标地址、目标端口等信息。
根据目标地址类型和地址解析方式,获取目标地址和端口号。
向目标地址发起连接请求,并返回连接成功的回包。
进程管理:

使用 goroutine 后台开启两个服务器交互进程。
通过 context 库进行进程管理,确保进程在必要时可以被关闭。
将客户端和目标之间的数据互相拷贝,使得数据能够在两者之间传递。

四、课后个人总结:

在这节课学习的内容中,我收获了很多关于Go语言编程的知识和技能。以下是我的感想:

Go语言的简洁和高效:通过学习这些基础标准库和相关功能,我深刻感受到Go语言的简洁和高效。标准库提供了丰富的功能,让编程变得更加简单和高效。

数据类型转换和字符串处理:学习了strconv和strings包,对于数据类型转换和字符串处理有了更深入的了解。这些工具使得在处理用户输入和数据转换时更加方便。

网络编程和HTTP库:了解了Go语言中的网络编程和net/http包,我现在能够编写简单的HTTP服务器和客户端,这对于开发网络应用和服务端程序非常有用。

文件操作和系统交互:通过os包的学习,我学会了如何在Go语言中进行文件操作和与操作系统进行交互,这对于处理文件和系统配置十分重要。

代理和鉴权:学习了socks5代理和鉴权机制,我对网络代理和安全认证有了更深刻的理解,这对于开发安全性较高的应用非常重要。

上下文处理:context包的学习使我了解了在Go语言中如何优雅地处理请求上下文,更好地控制请求的流程和生命周期。

本文作者:xyxsw
本文链接:https://xyxsw.ltd/2023/07/25/go%E8%AF%AD%E8%A8%80%E4%B8%89%E4%B8%AA%E5%B0%8F%E9%A1%B9%E7%9B%AE%20%EF%BD%9C%20%E9%9D%92%E8%AE%AD%E8%90%A5%E7%AC%94%E8%AE%B0/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可