我有这段代码,用 Python 编写。据我了解
如果任何本地接口收到该组/端口的多播消息,recv 将返回结果。
import sys
import socket
import struct
MULTICASTGROUP = "230.0.0.2"
MULTICASTPORT = 4450
hostname = socket.gethostname()
hosts = socket.gethostbyname_ex(hostname)
hostinterfaceips = hosts[2]
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', MULTICASTPORT))
for inf in hostinterfaceips:
sock.setsockopt(
socket.IPPROTO_IP,
socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(MULTICASTGROUP) + socket.inet_aton(inf)
)
data = sock.recv(1500)
print(data)
如何将此代码改编为 Go?据我所知。我很难理解 net 包,尤其是关于多播
func TestHost(t *testing.T) {
hostname, err := os.Hostname()
if err != nil {
t.Fatal(err)
}
fmt.Printf("hostname: %s\n", hostname)
addrs, err := net.LookupHost(hostname)
if err != nil {
t.Fatal(err)
}
for i, addr := range addrs {
fmt.Printf("%d: %s\n", i, addr)
}
}
事实证明,我的问题源于以下事实:net包默认禁用环回上的多播。您必须使用类似以下代码的内容重新打开它:
func createMulticastConnection(group string, port int) (*net.UDPConn, error) {
interfaces, err := getActiveInterfaces()
if err != nil {
return nil, err
}
var iface *net.Interface
// This grabs the first physical interface with multicast that is up.
for i := range interfaces {
if interfaces[i].Flags&net.FlagMulticast != 0 {
iface = interfaces[i]
break
}
}
if iface == nil {
return nil, fmt.Errorf("no valid interface found")
}
addr := net.UDPAddr{
IP: net.ParseIP(group),
Port: port,
}
conn, err := net.ListenUDP("udp", &addr)
if err != nil {
return nil, err
}
// This code enables loopback for multicast messages. By default,
// net disables loopback multicast and this is the only way
// to turn it back on.
if addr.IP.To4() != nil {
pc := ipv4.NewPacketConn(conn)
if err := pc.JoinGroup(iface, &addr); err != nil {
return nil, err
}
if err := pc.SetMulticastLoopback(true); err != nil {
return nil, err
}
} else if addr.IP.To16() != nil {
pc := ipv6.NewPacketConn(conn)
if err := pc.JoinGroup(iface, &addr); err != nil {
return nil, err
}
if err := pc.SetMulticastLoopback(true); err != nil {
return nil, err
}
}
}
// Returns a slice of "valid" addresses, i.e. ones
// that are "up" (whatever that means) and have an
// actual hardware address (meaning they aren't VPN interfaces)
func getActiveInterfaces() ([]*net.Interface, error) {
interfaces, err := net.Interfaces()
if err != nil {
return nil, err
}
ret := []*net.Interface{}
for i := range interfaces {
if interfaces[i].Flags&net.FlagUp != 0 &&
interfaces[i].HardwareAddr != nil {
ret = append(ret, &interfaces[i])
}
}
return ret, nil
}