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

2024年 2月 10日 109.5k 0

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

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 上运行:

  • 多播组的ip地址(问题中的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: %sn", buf[0:n])
}
}
}

登录后复制

以上就是多播在 golang 中的 Linux 上不起作用的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论