go - 我正在尝试使用 net 包构建一个简单的代理,但是当我不使用 go 例程时,上游没有发回任何数据

标签 go goroutine

我用 net 编写了这个简单的代理服务器包,我希望将来自 8001 的本地服务器的连接代理到通过 8000 的任何传入连接。当我转到浏览器并尝试它时,我收到拒绝连接错误。

package main

import (
    "net"
    "log"
    "io"
)

func main() {
    l, err := net.Listen("tcp", "localhost:8000")
    if err != nil {
        log.Fatal(err)
    }

    for {
        conn, err := l.Accept()
        if err != nil {
            log.Fatal(err)
        }
        go proxy(conn)
    }

}

func proxy(conn net.Conn) {
    defer conn.Close()
    upstream, err := net.Dial("tcp","localhost:8001")
    if err != nil {
        log.Print(err)
        return
    }
    defer upstream.Close()

    io.Copy(upstream, conn)

    io.Copy(conn, upstream)
}

但是如果我在代理函数中更改以下行

    io.Copy(upstream, conn)

    io.Copy(conn, upstream)



go io.Copy(upstream, conn)
   io.Copy(conn, upstream)

然后它按预期工作。不应该 io.Copy(upstream, conn)阻止io.Copy(conn, upstream) ?根据我的理解,conn应该只有在上游回复后才写?以及 io.Copy(upstream, conn) 的 go 例程如何?部分解决这个?

最佳答案

Shouldn't io.Copy block?



是的。 "Copy copies from src to dst until either EOF is reached on src or an error occurs." .由于这是一个网络连接,这意味着它在客户端关闭连接后返回。客户端是否以及何时关闭连接取决于应用程序协议(protocol)。例如,在 HTTP 中它可能永远不会发生。

How does having a goroutine solve this?



因为这样第二个 Copy 可以在客户端仍然连接时执行,从而允许上游写入其响应。没有 goroutine 就不会从上游读取任何内容,因此它可能会在其 write 调用时被阻塞。

客户端(大概)等待响应,代理等待客户端关闭连接,上游等待代理开始读取响应:没有人可以取得进展,你陷入了僵局。

关于go - 我正在尝试使用 net 包构建一个简单的代理,但是当我不使用 go 例程时,上游没有发回任何数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62339715/

相关文章:

go - golang 中奇怪的 pow 实现

go - 无法使用 WaitGroup 遍历文件夹

go - 追加不是线程安全的?

go - channel 僵局

go - struct{} 和 struct{}{} 在 Go 中如何工作?

go - 给定经纬度的地点的准确地址

go - 如何在 go 包之间传递 C 对象?

sql - 为什么还要在 Golang 中使用 *DB.exec() 或准备好的语句?

go - 根据key向特定go routine发送消息

go - 使用 goroutines 处理值并将结果收集到 slice 中