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 关于大棚监测的pcb板设计
  • ¥20 sim800c模块 at指令及平台
  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用
  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计