GO:为什么从客户端正在收听的地址拨号不起作用,但反之亦然?

时间:2016-01-08 09:53:44

标签: go server client client-server

我想知道为什么从客户端也在监听的地址拨号不起作用( 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())
}

1 个答案:

答案 0 :(得分:2)

"版本B"作为Go的POSIX默认设置SO_REUSEADDR的副作用,这将允许绑定到addr:port对,即使它已被现有连接使用。可以区分2个套接字,因为已建立的连接由(LocalAddr, LocalPort, RemoteAddr, RemotePort)的4元组标识。

"版本A"不起作用,因为在设置连接时,需要调用bind来设置请求的本地地址,并且已经有一个绑定到该端口的侦听套接字。

没有必要尝试利用这个漏洞,您应该使用2个端口进行客户端和服务器连接。