PHP-Herausgeber Xinyi, heute möchte ich mit Ihnen das Problem besprechen, dass Multicast in Golang unter Linux nicht funktioniert. Multicast ist eine Methode der Netzwerkkommunikation, die Daten zwischen einem einzelnen Sender und mehreren Empfängern überträgt. In Golang kann es jedoch vorkommen, dass Multicast unter Linux-Betriebssystemen nicht funktioniert. In diesem Artikel wird erläutert, warum dieses Problem auftritt, und es werden mögliche Lösungen bereitgestellt. Lasst uns beginnen!
Dieser Code sendet und empfängt Multicast-Pakete.
Dieser Code funktioniert unter Windows 10, aber nicht unter Linux: Warum?
Gepackter Inhalt (IP 230.0.0.1, Zielport 9001) wurde gesendet, aber der Multicast wurde von der Anwendung nicht empfangen
Paket (IP 230.0.0.2, Zielport 9002).
Was ist das Problem?
Um meine Anwendung zu testen, habe ich eine Linux-VM verwendet: Vielleicht ist das der Grund?
package main import ( "net" "os" "strconv" "time" "github.com/rs/zerolog" "golang.org/x/net/ipv4" ) const device1_tx_multicastAddr = "230.0.0.1" const device1_tx_udp_port = 9001 const device2_tx_multicastAddr = "230.0.0.2" const device2_tx_udp_port = 9002 const packetTxDelayMs = 1000 // const ethName = "Ethernet" // Windows const ethName = "eth0" // Linux const modeDevice2 = false // Device 1 //const modeDevice2 = true // Device 2 var logConsole zerolog.Logger func main() { logConsole = zerolog.New(os.Stderr).With().Timestamp(). Str("module", "main"). Logger().Output(zerolog.ConsoleWriter{Out: os.Stderr}). Level(zerolog.InfoLevel) // ********************************** // Initialize Tx localInterface := getInterfaceByName(ethName) logConsole.Info().Str("func", "main").Msg("localInterface: " + ethName) tx_multicastAddr := device1_tx_multicastAddr rx_multicastAddr := device2_tx_multicastAddr tx_udp_port := device1_tx_udp_port rx_udp_port := device2_tx_udp_port if modeDevice2 { tx_multicastAddr = device2_tx_multicastAddr rx_multicastAddr = device1_tx_multicastAddr tx_udp_port = device2_tx_udp_port rx_udp_port = device1_tx_udp_port } logConsole.Info().Str("func", "main").Msg("Open Tx UDP port " + tx_multicastAddr + ":" + strconv.Itoa(tx_udp_port) + "...") remoteDeviceUdpAddr, err := net.ResolveUDPAddr("udp4", tx_multicastAddr+":"+strconv.Itoa(tx_udp_port)) if err != nil { panic(err) } localDeviceUdpAddr, err2 := net.ResolveUDPAddr("udp4", localInterface.String()+":"+strconv.Itoa(rx_udp_port)) if err2 != nil { panic(err2) } logConsole.Info().Str("func", "main").Msg("Listen UDP: " + localDeviceUdpAddr.String() + "...") localDevice, err2 := net.ListenUDP("udp4", localDeviceUdpAddr) if err2 != nil { panic(err2) } // ********************************** // Initialize Rx udpReceiver := ipv4.NewPacketConn(localDevice) ief, errInterface := net.InterfaceByName(ethName) if errInterface != nil { localDevice.Close() panic(errInterface) } logConsole.Info().Str("func", "main").Msg("Join Multicast: " + rx_multicastAddr + "...") err = udpReceiver.JoinGroup(ief, &net.UDPAddr{IP: net.ParseIP(rx_multicastAddr)}) if err != nil { localDevice.Close() panic(err) } // ********************************** // Run Rx/Tx tasks go sendData(localDevice, remoteDeviceUdpAddr, packetTxDelayMs) receivedData(udpReceiver) } // ************************************************* func sendData(localDevice *net.UDPConn, remoteDeviceUdpAddr *net.UDPAddr, packetDelay uint) { data := []byte("1234567890") for { //logConsole.Info().Str("func", "sendData").Msg("Send...") _, err := localDevice.WriteTo(data, remoteDeviceUdpAddr) if err != nil { panic(err) } time.Sleep(time.Duration(packetDelay) * time.Millisecond) } } func receivedData(receiver *ipv4.PacketConn) { buf := make([]byte, 1500) for { n, _, _, err := receiver.ReadFrom(buf) if err == nil { logConsole.Info().Str("func", "receivedData").Msg("Receive Data: " + string(buf[0:n])) } } } // ************************************************* func getInterfaceByName(name string) net.IP { ief, err := net.InterfaceByName(name) if err != nil { panic(err) } addrs, err := ief.Addrs() if err != nil { panic(err) } var ipAddr net.IP for _, addr := range addrs { ipAddr = addr.(*net.IPNet).IP.To4() if ipAddr != nil { break } } if ipAddr == nil { panic("ipAddr is nil") } return ipAddr }
Wenn Sie die Anwendung so ändern, dass sie auf einer der folgenden IP-Adressen lauscht, wird sie unter Linux und MacOS ausgeführt:
rx_multicastaddr
in der Frage)0.0.0.0
). Aber es ist nicht klar, ob es funktioniert, wenn es die IP-Adresse eines Netzwerks abhört (z. B. 192.168.0.5
). Basierend auf meinen Tests und der Beschreibung in der Frage funktioniert es unter Windows, aber nicht unter Linux oder MacOS. Ich konnte keine verlässliche Quelle finden, die dieses Verhalten beschreibt.
Nachfolgend finden Sie eine vereinfachte Demonstration der Akzeptanzflagge.
Führen Sie es auf Gerät 1 mit dem folgenden Befehl aus (ersetzen Sie den Schnittstellennamen durch den Namen Ihres Geräts):
go run . -listen 230.0.0.1:9001 -join 230.0.0.1:9001 -send 230.0.0.2:9002 -ifname eth0
Führen Sie es auf Gerät 2 mit dem folgenden Befehl aus (ersetzen Sie den Schnittstellennamen durch den Schnittstellennamen Ihres Geräts):
go run . -listen 0.0.0.0:9002 -join 230.0.0.2:9002 -send 230.0.0.1:9001 -ifname ethernet
package main import ( "flag" "log" "net" "time" "golang.org/x/net/ipv4" ) var ( listen string join string send string ifname string ) func main() { flag.StringVar(&listen, "listen", "230.0.0.1:9001", "") flag.StringVar(&join, "join", "230.0.0.1:9001", "the multicast group address to receive data from") flag.StringVar(&send, "send", "230.0.0.2:9002", "the multicast group address to send data to") flag.StringVar(&ifname, "ifname", "eth0", "the name of the interface") flag.Parse() itf, err := net.InterfaceByName(ifname) if err != nil { panic(err) } groupAddr, err := net.ResolveUDPAddr("udp4", join) if err != nil { panic(err) } c, err := net.ListenPacket("udp4", listen) if err != nil { panic(err) } defer c.Close() p := ipv4.NewPacketConn(c) if err := p.JoinGroup(itf, &net.UDPAddr{IP: groupAddr.IP}); err != nil { panic(err) } log.Printf("join multicast group %s, waiting...", join) go sendData(c, send) receivedData(p) } func sendData(c net.PacketConn, target string) { data := []byte(ifname) addr, err := net.ResolveUDPAddr("udp4", target) if err != nil { panic(err) } for { _, err := c.WriteTo(data, addr) if err != nil { panic(err) } time.Sleep(time.Second) } } func receivedData(receiver *ipv4.PacketConn) { buf := make([]byte, 1500) for { n, _, _, err := receiver.ReadFrom(buf) if err == nil { log.Printf("Receive Data from: %s\n", buf[0:n]) } } }
Das obige ist der detaillierte Inhalt vonMulticast funktioniert unter Linux in Golang nicht. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!