我写了这个简单的代理服务器与 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应该在上游回复后才写?那么有一个go的例程是怎样的呢?io.Copy(upstream, conn)
部分解决这个问题?
io.Copy不应该屏蔽吗?
是的。"从src复制到dst,直到src上达到EOF或发生错误。". 由于这是一个网络连接,这意味着它在客户端关闭连接后返回。客户端是否以及何时关闭连接取决于应用协议。例如,在HTTP中,它可能永远不会发生。
有一个goroutine如何解决这个问题?
因为这样的话,第二个Copy可以在客户端还在连接的时候执行,让上游写出它的响应。如果没有goroutine,什么也没有从上游读取,所以很可能在它的写调用上被阻塞。
客户端(大概)等待响应,代理等待客户端关闭连接,上游等待代理开始读取响应:没有人可以取得进展,你就陷入了死锁。