Go语言端口转发程序读取缓冲区后无法转发、连接超时问题
Go端口转发程序超时与报错问题修复方案
核心问题梳理
- 1 连接接受逻辑错误:
tcpListener.Accept()放在for循环外部,程序仅能接收1次客户端连接,后续所有连接都会因为得不到处理直接超时。同时没有处理Accept返回的错误,连接异常时无法感知。 - 2 闭包变量捕获错误:匿名goroutine直接捕获外部的
conn变量,多个goroutine会共用同一个连接变量,引发并发数据混乱。 - 3 首包数据丢失:用
bufio.Reader读取了连接的前1024字节存入本地buffer后,没有将这部分数据转发到目标服务,导致后端收到的请求不完整,无法正常响应客户端,也是你提到的读取后未正常停止的根因。 - 4 后端Dial参数错误:调用
Dial连接目标服务时仅传入了IP参数,没有拼接端口号,根本无法建立到目标服务的连接,直接触发转发失败报错。 - 5 defer位置错误:
forward函数中先执行io.Copy再注册defer,若io.Copy执行过程中出错,连接无法正常关闭,会导致连接泄漏。 - 6 语法错误:短变量声明符号
:=被错误拆分为: =,代码存在编译异常。
修复步骤
- 将
Accept逻辑移入for循环内部,每次循环处理一个新的客户端连接,同时处理Accept返回的错误。 - 将
conn作为参数传入匿名goroutine,避免闭包变量捕获问题。 - 删掉多余的
bufio.Reader读取逻辑,若需要统计流量大小可以在forward逻辑中处理,不要提前读取连接数据。 - 修正Dial参数,拼接IP和端口:
ip + ":" + port。 - 调整
forward函数中defer的位置,注册延迟关闭后再执行io.Copy。 - 修正所有短变量声明的语法错误。
修复后完整代码
package main import ( "io" "log" "net" "time" ) func main() { tcpAddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:2222") if err != nil { log.Fatalln("resolve addr failed:", err) } tcpListener, err := net.ListenTCP("tcp", tcpAddr) if err != nil { log.Fatalln("listen failed:", err) } log.Println("port forward start on 2222") for { // 每次循环接受新连接 conn, err := tcpListener.Accept() if err != nil { log.Println("accept conn failed:", err) continue } // 连接作为参数传入goroutine,避免闭包问题 go func(c net.Conn) { handleConnection(c, "192.168.1.107", "2222") }(conn) } } func forward(src, dest net.Conn) { // 先注册延迟关闭,再执行拷贝 defer src.Close() defer dest.Close() _, err := io.Copy(src, dest) if err != nil { log.Println("forward data failed:", err) } } func handleConnection(c net.Conn, ip string, port string) { dialCheck := net.Dialer{ Timeout: 5 * time.Second, } // 拼接IP和端口 remote, err := dialCheck.Dial("tcp", ip + ":" + port) if err != nil { log.Println("dial remote failed:", err) _ = c.Close() return } go forward(c, remote) go forward(remote, c) }
内容的提问来源于stack exchange,提问作者Bayu Anggara
相关产品推荐
相关产品推荐

