douzang7928 2016-01-08 09:53 采纳率: 100%
浏览 12
已采纳

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

I wonder why dialing from the address on which the client is also listening does not work (Version A) but listening on the connection address the client is dialing to the server does actually work (Version B)?!

Can someone explain this to me. Go is new to me and I still learning a lot of things.

Here is an example:

Server Programm:

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
", con.LocalAddr())
        Printf("RemoteAddr: %v
", con.RemoteAddr())
    }
}

Client version A (not working):

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
", con.LocalAddr())
    Printf("RemoteAddr: %v
", con.RemoteAddr())
}

Client version B (working):

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
", conn.LocalAddr())
    Printf("RemoteAddr: %v
", conn.RemoteAddr())
}
  • 写回答

1条回答 默认 最新

  • doujiao7483 2016-01-08 15:44
    关注

    "Version B" works as a side effect of the Go's POSIX default of setting SO_REUSEADDR, which will allow binding to an addr:port pair even if it's in use by an existing connection. The 2 sockets can be differentiated, because the established connection is identified by the 4-tuple of (LocalAddr, LocalPort, RemoteAddr, RemotePort).

    "Version A" doesn't work, because when setting up the connection it needs to call bind to set the requested local address, and there is already a listening socket bound to that port.

    There's no need to try and exploit this loophole, and you should use 2 ports for your client and server connections.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在炒股软件中,爬到我想看的日k线
  • ¥15 51单片机中C语言怎么做到下面类似的功能的函数(相关搜索:c语言)
  • ¥15 seatunnel 怎么配置Elasticsearch
  • ¥15 PSCAD安装问题 ERROR: Visual Studio 2013, 2015, 2017 or 2019 is not found in the system.
  • ¥15 (标签-MATLAB|关键词-多址)
  • ¥15 关于#MATLAB#的问题,如何解决?(相关搜索:信噪比,系统容量)
  • ¥500 52810做蓝牙接受端
  • ¥15 基于PLC的三轴机械手程序
  • ¥15 多址通信方式的抗噪声性能和系统容量对比
  • ¥15 winform的chart曲线生成时有凸起