php小编新一,今天要和大家讨论的是在golang中多播在Linux上不起作用的问题。多播是一种网络通信方式,可以在一个发送者和多个接收者之间传输数据。然而,在golang中,我们可能会遇到在Linux操作系统上多播不起作用的情况。本文将解释为什么会出现这个问题,并提供可能的解决方案。让我们开始吧!
此代码发送和接收多播包。
此代码适用于 windows 10,但不适用于 linux:为什么?
已发送打包内容(ip 230.0.0.1,目标端口 9001),但应用程序未接收多播
数据包(ip 230.0.0.2,目标端口 9002)。
问题是什么?
为了测试我的应用程序,我使用了 linux vm:也许,这就是原因?
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 }
修改应用程序以侦听以下 ip 地址之一将使其在 linux 和 macos 上运行:
rx_multicastaddr
)0.0.0.0
)。但尚不清楚当它侦听 nic 的 ip 地址(例如 192.168.0.5
)时是否可以工作。根据我的测试和问题中的描述,它可以在 windows 上运行,但不能在 linux 或 macos 上运行。我还找不到描述这种行为的权威来源。
下面是一个接受标志的简化演示。
在设备 1 上,使用以下命令运行它(将接口名称替换为您的设备的名称):
go run . -listen 230.0.0.1:9001 -join 230.0.0.1:9001 -send 230.0.0.2:9002 -ifname eth0
在设备 2 上,使用以下命令运行它(将接口名称替换为您设备的接口名称):
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]) } } }
以上是多播在 golang 中的 Linux 上不起作用的详细内容。更多信息请关注PHP中文网其他相关文章!