0

I need to write multicast listener on Go. I faces the problem of twicing packets when I read it. It seems that I need to set IP_MULTICAST_LOOP to false. It is not easy to do in Go.

I found this post. It seems that it should work. But I still get copies of the same host. How should it be done?

ipAddr, err := net.ResolveUDPAddr("udp", groupAddress)
if err != nil {...}

iface, err := net.InterfaceByName("en0")
if err != nil {...}

conn, err := net.ListenPacket("udp4", groupAddress)
if err != nil {...}

pc := ipv4.NewPacketConn(conn)

if err := pc.JoinGroup(iface, ipAddr); err != nil {...}

if err := pc.SetMulticastLoopback(false); err != nil {...}


if loop, err := pc.MulticastLoopback(); err == nil {...}

buf := make([]byte, 1024)
for {

    n, _, addr, err := pc.ReadFrom(buf)
    if err != nil {...}

    fmt.Printf("recv from %v: [%s] \n", addr, buf[:n])
}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Yura
  • 969
  • 14
  • 33

1 Answers1

0

The simplest way is to use the ListenMulticastUDP wrapper in the net package, as actually already explained in the other SO answer you point to, How to set IP_MULTICAST_LOOP on multicast UDPConn in Golang.

If you follow the implementation of ListenMulticastUDP(), you will see that at a certain point it calls setIPv4MulticastLoopback(fd, false).

If you need something more advanced, the documentation of ListenMulticastUDP() suggests to look at https://godoc.org/golang.org/x/net/ipv4 and https://godoc.org/golang.org/x/net/ipv6, which document extensively how to do multicast in Go.

Here is some minimal code (tested on MacOS, but platform-independent) that shows how to use ListenMulticastUDP():

func main() {
    // MDNS (https://en.wikipedia.org/wiki/Multicast_DNS)
    groupAddress := "224.0.0.251:5353"
    ifaceName := "en0"
    if err := run(groupAddress, ifaceName); err != nil {
        fmt.Fprintln(os.Stderr, "error:", err)
        os.Exit(1)
    }
}

func run(groupAddr string, ifaceName string) error {
    iface, err := net.InterfaceByName(ifaceName)
    if err != nil {
        return err
    }

    gaddr, err := net.ResolveUDPAddr("udp", groupAddr)
    if err != nil {
        return err
    }

    conn, err := net.ListenMulticastUDP("udp", iface, gaddr)
    if err != nil {
        return err
    }

    buf := make([]byte, 1024)
    for {
        n, addr, err := conn.ReadFromUDP(buf)
        if err != nil {
            return err
        }
        fmt.Printf("recv %4d bytes from %v\n", n, addr)
    }
}
marco.m
  • 4,573
  • 2
  • 26
  • 41