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: %s\n", buf[0:n])
}
}
}
以上就是多播在 golang 中的 Linux 上不起作用的详细内容,更多请关注编程网其它相关文章!