You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang带流量限制Socks5代理转发后下载速度归零问题

带流量限制的Socks5代理转发后下载速度归零问题排查

我实现了一个带流量限制的Golang Socks5代理(监听10801端口),将流量转发至另一个无流量限制的Socks5代理(监听10802端口)。使用命令curl -x socks5://127.0.0.1:10801 -O https://mirrors.xxxx.iso测试下载时,初期下载正常且流量限制生效,但一段时间后速度变为0。

我尝试了两种流量限制的Copy实现方式,即使将缓冲区增大至64*1024,问题仍存在。

带流量限制的代理代码

package main

import (
    "fmt"
    "github.com/juju/ratelimit"
    "io"
    "net"
)

var nextProxy = "127.0.0.1:10802"

func main() {
    server, err := net.Listen("tcp", ":10801")
    if err != nil {
        fmt.Printf("Listen failed: %v\n", err)
        return
    }

    for {
        client, err := server.Accept()
        if err != nil {
            fmt.Printf("Accept failed: %v", err)
            continue
        }

        go handle(client)
    }
}

func handle(conn net.Conn) {

    // add close
    defer conn.Close()

    // next socks5 proxy
    nextConn, err := net.Dial("tcp", nextProxy)
    if err != nil {
        fmt.Println("Failed to connect to next proxy:", err)
        conn.Close()
        return
    }
    defer nextConn.Close()

    go func() {
        _, err := Copy(nextConn, conn)
        if err != nil {
            fmt.Println("Error copying data to next proxy:", err)
            conn.Close()
        }
    }()

    _, err = Copy(conn, nextConn)
    if err != nil {
        fmt.Println("Error copying data from next proxy:", err)
        conn.Close()
    }
}

func Copy(left io.Writer, right io.Reader) (int64, error) {
    
    right = ratelimit.Reader(right, ratelimit.NewBucketWithRate(102400, 102400))

    return io.Copy(left, right)
}

另一种流量限制Copy实现

我还尝试了另一种Copy实现:

func copyWithRateLimit(dst io.Writer, src io.Reader, limiter *ratelimit.Bucket) {
    // buffer
    buf := make([]byte, 32*1024) // 32KB buffer
    for {
        n, err := src.Read(buf)
        if err != nil {
            if err == io.EOF {
                return
            }
            fmt.Println("Error reading from source:", err)
            return
        }

        // Rate limit the data
        if limit := limiter.WaitMaxDuration(int64(n), time.Second); !limit {
            fmt.Println("Error rate limiting:", err)
            return
        }

        if _, err := dst.Write(buf[:n]); err != nil {
            fmt.Println("Error writing to destination:", err)
            return
        }
    }
}

即使将缓冲区增大至64*1024,速度仍会归零并最终无法正常工作。


无流量限制的Socks5代理代码

package main

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

func main() {
    server, err := net.Listen("tcp", ":10802")
    if err != nil {
        fmt.Printf("Listen failed: %v\n", err)
        return
    }

    for {
        client, err := server.Accept()
        if err != nil {
            fmt.Printf("Accept failed: %v", err)
            continue
        }

        go process(client)
    }
}

func process(client net.Conn) {
    if err := Socks5Auth(client); err != nil {
        fmt.Println("auth error:", err)
        client.Close()
        return
    }

    target, err := Socks5Connect(client)
    if err != nil {
        fmt.Println("connect error:", err)
        client.Close()
        return
    }

    Socks5Forward(client, target)
}

func Socks5Auth(client net.Conn) (err error) {
    buf := make([]byte, 256)

    n, err := io.ReadFull(client, buf[:2])
    if n != 2 {
        return errors.New("reading header: " + err.Error())
    }

    ver, nMethods := int(buf[0]), int(buf[1])
    if ver != 5 {
        return errors.New("invalid version")
    }

    n, err = io.ReadFull(client, buf[:nMethods])
    if n != nMethods {
        return errors.New("reading methods: " + err.Error())
    }

    n, err = client.Write([]byte{0x05, 0x00})
    if n != 2 || err != nil {
        return errors.New("write rsp: " + err.Error())
    }

    return nil
}

func Socks5Connect(client net.Conn) (net.Conn, error) {
    buf := make([]byte, 256)

    n, err := io.ReadFull(client, buf[:4])
    if n != 4 {
        return nil, errors.New("read header: " + err.Error())
    }

    ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3]
    if ver != 5 || cmd != 1 {
        return nil, errors.New("invalid ver/cmd")
    }

    addr := ""
    switch atyp {
    case 1:
        n, err = io.ReadFull(client, buf[:4])
        if n != 4 {
            return nil, errors.New("invalid IPv4: " + err.Error())
        }
        addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])

    case 3:
        n, err = io.ReadFull(client, buf[:1])
        if n != 1 {
            return nil, errors.New("invalid hostname: " + err.Error())
        }
        addrLen := int(buf[0])

        n, err = io.ReadFull(client, buf[:addrLen])
        if n != addrLen {
            return nil, errors.New("invalid hostname: " + err.Error())
        }
        addr = string(buf[:addrLen])

    case 4:
        return nil, errors.New("IPv6: no supported yet")

    default:
        return nil, errors.New("invalid atyp")
    }

    n, err = io.ReadFull(client, buf[:2])
    if n != 2 {
        return nil, errors.New("read port: " + err.Error())
    }
    port := binary.BigEndian.Uint16(buf[:2])

    destAddrPort := fmt.Sprintf("%s:%d", addr, port)
    dest, err := net.Dial("tcp", destAddrPort)
    if err != nil {
        return nil, errors.New("dial dst: " + err.Error())
    }

    n, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
    if err != nil {
        dest.Close()
        return nil, errors.New("write rsp: " + err.Error())
    }

    return dest, nil
}

func Socks5Forward(client, target net.Conn) {

    forward := func(src, dest net.Conn) {
        defer src.Close()
        defer dest.Close()

        io.Copy(src, dest)
    }

    go forward(client, target)
    go forward(target, client)
}

测试情况

在同一机器上启动两个程序并使用curl下载文件,出现速度归零的问题。

我进行了以下测试:

  • 将第一个代理的带宽设置为与机器一致,curl可正常下载文件;
  • 仅通过第二个Socks5代理下载,并在其上设置流量限制,curl正常下载;
  • 两个代理设置相同的流量限制,curl可正常下载。

现需排查为何仅第一个代理设置流量限制时,会出现下载速度归零的问题。

内容的提问来源于stack exchange,提问作者Jacky Lam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 05:50:55