V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gesse
V2EX  ›  程序员

讨论一个 UDP 问题,关于监听。

  •  
  •   gesse · 2 天前 · 1688 次点击

    服务器有多个 IP ,UDP 监听 0.0.0.0:1234 ,并接收 UDP 数据。 如果客户端通过其中一个 IP 和 1234 端口向服务器发送了 UDP 数据,怎么获取这个客户端连接的是服务器端那个 IP ?

    C 语言我知道是可以用 IP_PKTINFO 套接字选项来实现的。

    golang 不是很熟悉,有类似的实现吗?

    10 条回复    2024-06-27 15:56:01 +08:00
    kuanat
        1
    kuanat  
       2 天前
    如果是 connected 可以通过 UDPConn.LocalAddr() 获得,如果是 unconnected 要通过 ReadMsgUDP 的 oob 信息获取,底层实现应该还是 IP_PKTINFO 。

    如果嫌麻烦可以每个 ip 对应一个实例或者 goroutine ,这样就知道本地绑定的 ip 了。
    povsister
        2
    povsister  
       2 天前
    拿四层的 IP 头,看 DST IP
    go 的 socket 库是有函数可以顺带拿到 IP 头的
    GeekGao
        4
    GeekGao  
       2 天前
    ```
    package main

    import (
    "fmt"
    "net"
    )

    func main() {
    addr := "0.0.0.0:1234"
    conn, err := net.ListenPacket("udp", addr)
    if err != nil {
    fmt.Println("ListenPacket:", err)
    return
    }
    defer conn.Close()

    buf := make([]byte, 1024)
    for {
    n, addr, err := conn.ReadFrom(buf)
    if err != nil {
    fmt.Println("ReadFrom:", err)
    continue
    }
    fmt.Println("Received:", string(buf[:n]), "from", addr)
    }
    }
    ```
    zhs227
        5
    zhs227  
       2 天前   ❤️ 1
    最近刚好在处理一个与这个有关的问题,楼主需要的是 udp 连接中 server 端的 IP (由于多 IP 监听导致的,即 ADDR_ANY ),不是需要客户端的 IP 与端口。
    在 deepseek 中找了个答案好像能用(用 gpt-o 试了得到的答案无法运行),性能不太清楚怎么样。

    ```
    package main

    import (
    "fmt"
    "net"
    "golang.org/x/net/ipv4"
    )

    func main() {
    addr, err := net.ResolveUDPAddr("udp", "0.0.0.0:1234")
    if err != nil {
    fmt.Println("Error resolving UDP address:", err)
    return
    }

    conn, err := net.ListenUDP("udp", addr)
    if err != nil {
    fmt.Println("Error listening on UDP:", err)
    return
    }
    defer conn.Close()

    pconn := ipv4.NewPacketConn(conn)
    if err := pconn.SetControlMessage(ipv4.FlagDst, true); err != nil {
    fmt.Println("Error setting control message:", err)
    return
    }

    buffer := make([]byte, 1024)
    for {
    n, cm, src, err := pconn.ReadFrom(buffer)
    if err != nil {
    fmt.Println("Error reading from UDP:", err)
    continue
    }

    if cm != nil && cm.Dst != nil {
    fmt.Printf("Received %d bytes from %s to %s\n", n, src, cm.Dst)
    } else {
    fmt.Printf("Received %d bytes from %s\n", n, src)
    }
    }
    }
    ```
    zhs227
        6
    zhs227  
       2 天前
    虽是 AI 生成的,但我实际运行进行了验证是可用的。

    # ./udp
    Received 6 bytes from 192.168.1.109:53900 to 192.168.1.60
    ^C
    gesse
        7
    gesse  
    OP
       2 天前
    ipv4.NewPacketConn(conn).SetControlMessage(ipv4.FlagDst, true)

    是可以的
    bowser1701
        8
    bowser1701  
       2 天前   ❤️ 1
    @gesse `net.UDPConn` 有 `ReadMsgUDP` 可以读到
    lysShub
        9
    lysShub  
       2 天前
    @gesse

    是用的域名吗?

    client 用 DialUDP 连 Server ,RemoteAddr() 就是服务器 IP
    lysShub
        10
    lysShub  
       2 天前
    楼上的什么 raw socket 都来,不至于
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2298 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 10:37 · PVG 18:37 · LAX 03:37 · JFK 06:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.