Multicast funktioniert unter Linux in Golang nicht

WBOY
Freigeben: 2024-02-10 16:42:07
nach vorne
996 Leute haben es durchsucht

多播在 golang 中的 Linux 上不起作用

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!

Frageninhalt

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
}
Nach dem Login kopieren

Workaround

Wenn Sie die Anwendung so ändern, dass sie auf einer der folgenden IP-Adressen lauscht, wird sie unter Linux und MacOS ausgeführt:

  • Die IP-Adresse der Multicast-Gruppe (rx_multicastaddr in der Frage)
  • Wildcard-Adresse (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
Nach dem Login kopieren

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
Nach dem Login kopieren
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])
        }
    }
}
Nach dem Login kopieren

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!

Verwandte Etiketten:
Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!