Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Multicast tidak berfungsi pada linux dalam golang

Multicast tidak berfungsi pada linux dalam golang

WBOY
WBOYke hadapan
2024-02-10 16:42:07996semak imbas

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

PHP editor Xinyi, hari ini saya ingin membincangkan dengan anda masalah bahawa multicast dalam golang tidak berfungsi pada Linux. Multicast ialah kaedah komunikasi rangkaian yang menghantar data antara satu penghantar dan berbilang penerima. Walau bagaimanapun, dalam golang, kita mungkin menghadapi situasi di mana multicast tidak berfungsi pada sistem pengendalian Linux. Artikel ini akan menerangkan mengapa masalah ini berlaku dan menyediakan penyelesaian yang mungkin. Mari mulakan!

Kandungan soalan

Kod ini menghantar dan menerima paket multicast.

Kod ini berfungsi pada windows 10 tetapi tidak pada linux: kenapa?

Kandungan berpakej (ip 230.0.0.1, port destinasi 9001) telah dihantar, tetapi siaran berbilang tidak diterima oleh aplikasi

Paket (ip 230.0.0.2, port destinasi 9002).

Apa masalahnya?

Untuk menguji aplikasi saya, saya menggunakan linux vm: mungkin, itu sebabnya?

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
}

Penyelesaian

Mengubah suai aplikasi untuk mendengar pada salah satu alamat ip berikut akan menjadikannya berjalan pada linux dan macos:

  • Alamat ip kumpulan multicast (rx_multicastaddr dalam soalan)
  • Alamat kad liar (0.0.0.0).

Tetapi tidak jelas sama ada ia akan berfungsi apabila ia mendengar pada alamat ip nic (cth. 192.168.0.5). Berdasarkan ujian saya dan penerangan dalam soalan, ia berfungsi pada windows, tetapi bukan pada linux atau macos. Saya tidak dapat mencari sumber berwibawa yang menerangkan tingkah laku ini.

Di bawah ialah demonstrasi ringkas bendera penerimaan.

Pada peranti 1, jalankannya dengan arahan berikut (gantikan nama antara muka dengan nama peranti anda):

go run . -listen 230.0.0.1:9001 -join 230.0.0.1:9001 -send 230.0.0.2:9002 -ifname eth0

Pada peranti 2, jalankannya dengan arahan berikut (gantikan nama antara muka dengan nama antara muka peranti anda):

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])
        }
    }
}

Atas ialah kandungan terperinci Multicast tidak berfungsi pada linux dalam golang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam