GO:为什么从客户端正在监听的地址拨号不起作用,而相反的地址呢?
GO: Why does dialing from the address on which the client is listening not work, but the opposite does?
我想知道为什么从客户端也在监听的地址拨号不起作用(Version A
)但是监听客户端正在拨号的连接地址服务器确实有效 (Version B
)?!
谁能给我解释一下。 Go
对我来说是新手,我仍然学到很多东西。
这是一个例子:
服务器程序:
package main
import . "fmt"
import "net"
import "os"
func main() {
Println("server")
var listener, listenerError = net.Listen("tcp", "localhost:8080")
if listenerError != nil {
Println(listenerError)
os.Exit(1)
}
for {
con, _ := listener.Accept() // I don't care about the error in this example
Printf("LocalAddr: %v\n", con.LocalAddr())
Printf("RemoteAddr: %v\n", con.RemoteAddr())
}
}
客户端版本 A(不工作):
package main
import "net"
import . "fmt"
import "os"
func main() {
var listener, listenerError = net.Listen("tcp", "localhost:0")
if listenerError != nil {
Println(listenerError)
os.Exit(1)
}
var dialer = new(net.Dialer)
dialer.LocalAddr = listener.Addr()
con, err := dialer.Dial("tcp", "localhost:8080")
if err != nil {
// dial tcp 127.0.0.1:60229->127.0.0.1:8080: bind: address already in use
Println(err)
os.Exit(2)
}
Printf("LocalAddr: %v\n", con.LocalAddr())
Printf("RemoteAddr: %v\n", con.RemoteAddr())
}
客户端版本 B(工作):
package main
import "net"
import . "fmt"
import "os"
func main() {
Println("client")
con, err := net.Dial("tcp", "localhost:8080")
if err != nil {
Println(err)
os.Exit(2)
}
// magic happens here
var listener, listenerError = net.Listen("tcp", con.LocalAddr().String())
if listenerError != nil {
Println(listenerError)
os.Exit(1)
}
Println("LISTENING")
conn, _ := listener.Accept() // will accept on con.LocalAddr()
Printf("LocalAddr: %v\n", conn.LocalAddr())
Printf("RemoteAddr: %v\n", conn.RemoteAddr())
}
"Version B" 是 Go 的 POSIX 默认设置 SO_REUSEADDR
的副作用,它允许绑定到 addr:port
对,即使它被使用现有连接。 2个套接字是可以区分的,因为建立的连接是由(LocalAddr, LocalPort, RemoteAddr, RemotePort)
的四元组标识的。
"Version A" 不起作用,因为在建立连接时需要调用 bind
来设置请求的本地地址,并且已经有一个监听套接字绑定到该端口。
没有必要尝试利用这个漏洞,您应该为客户端和服务器连接使用 2 个端口。
我想知道为什么从客户端也在监听的地址拨号不起作用(Version A
)但是监听客户端正在拨号的连接地址服务器确实有效 (Version B
)?!
谁能给我解释一下。 Go
对我来说是新手,我仍然学到很多东西。
这是一个例子:
服务器程序:
package main
import . "fmt"
import "net"
import "os"
func main() {
Println("server")
var listener, listenerError = net.Listen("tcp", "localhost:8080")
if listenerError != nil {
Println(listenerError)
os.Exit(1)
}
for {
con, _ := listener.Accept() // I don't care about the error in this example
Printf("LocalAddr: %v\n", con.LocalAddr())
Printf("RemoteAddr: %v\n", con.RemoteAddr())
}
}
客户端版本 A(不工作):
package main
import "net"
import . "fmt"
import "os"
func main() {
var listener, listenerError = net.Listen("tcp", "localhost:0")
if listenerError != nil {
Println(listenerError)
os.Exit(1)
}
var dialer = new(net.Dialer)
dialer.LocalAddr = listener.Addr()
con, err := dialer.Dial("tcp", "localhost:8080")
if err != nil {
// dial tcp 127.0.0.1:60229->127.0.0.1:8080: bind: address already in use
Println(err)
os.Exit(2)
}
Printf("LocalAddr: %v\n", con.LocalAddr())
Printf("RemoteAddr: %v\n", con.RemoteAddr())
}
客户端版本 B(工作):
package main
import "net"
import . "fmt"
import "os"
func main() {
Println("client")
con, err := net.Dial("tcp", "localhost:8080")
if err != nil {
Println(err)
os.Exit(2)
}
// magic happens here
var listener, listenerError = net.Listen("tcp", con.LocalAddr().String())
if listenerError != nil {
Println(listenerError)
os.Exit(1)
}
Println("LISTENING")
conn, _ := listener.Accept() // will accept on con.LocalAddr()
Printf("LocalAddr: %v\n", conn.LocalAddr())
Printf("RemoteAddr: %v\n", conn.RemoteAddr())
}
"Version B" 是 Go 的 POSIX 默认设置 SO_REUSEADDR
的副作用,它允许绑定到 addr:port
对,即使它被使用现有连接。 2个套接字是可以区分的,因为建立的连接是由(LocalAddr, LocalPort, RemoteAddr, RemotePort)
的四元组标识的。
"Version A" 不起作用,因为在建立连接时需要调用 bind
来设置请求的本地地址,并且已经有一个监听套接字绑定到该端口。
没有必要尝试利用这个漏洞,您应该为客户端和服务器连接使用 2 个端口。