You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将TCP/IP组播Python代码转换为Go语言实现

将Python组播代码转换为Go语言实现

原Python代码功能说明

原Python代码实现了以下功能:

  • 创建UDP套接字
  • 开启地址复用选项
  • 绑定到指定端口(监听所有本地接口)
  • 将所有本地IPv4地址加入指定组播组
  • 接收组播消息并打印输出

原Python代码

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语言实现

以下是对应功能的Go代码,修复了原测试代码中获取本地IP的问题(net.LookupHost可能返回非本地IP,改用net.InterfaceAddrs精准获取本地IPv4地址),并完成组播核心逻辑:

package main

import (
	"fmt"
	"net"
	"os"
	"syscall"
)

const (
	multicastGroup = "230.0.0.2"
	multicastPort  = 4450
)

func main() {
	// 创建UDP套接字并绑定到所有接口的指定端口
	conn, err := net.ListenUDP("udp4", &net.UDPAddr{
		IP:   net.IPv4zero,
		Port: multicastPort,
	})
	if err != nil {
		fmt.Printf("创建套接字失败: %v\n", err)
		os.Exit(1)
	}
	defer conn.Close()

	// 设置SO_REUSEADDR选项,允许多进程绑定同一端口
	file, err := conn.File()
	if err != nil {
		fmt.Printf("获取套接字文件描述符失败: %v\n", err)
		os.Exit(1)
	}
	defer file.Close()

	if err := syscall.SetsockoptInt(int(file.Fd()), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
		fmt.Printf("设置SO_REUSEADDR失败: %v\n", err)
		os.Exit(1)
	}

	// 获取所有非环回的本地IPv4地址
	localIPs, err := getLocalIPv4Addresses()
	if err != nil {
		fmt.Printf("获取本地IP失败: %v\n", err)
		os.Exit(1)
	}

	// 将每个本地IP加入目标组播组
	groupAddr := net.ParseIP(multicastGroup).To4()
	for _, ip := range localIPs {
		mreq := &syscall.IPMreq{
			Multiaddr: [4]byte{groupAddr[0], groupAddr[1], groupAddr[2], groupAddr[3]},
			Interface: [4]byte{ip[0], ip[1], ip[2], ip[3]},
		}
		if err := syscall.SetsockoptIPMreq(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq); err != nil {
			fmt.Printf("IP %s 加入组播组失败: %v\n", ip.String(), err)
			continue
		}
		fmt.Printf("IP %s 已成功加入组播组 %s:%d\n", ip.String(), multicastGroup, multicastPort)
	}

	// 阻塞接收组播消息
	buf := make([]byte, 1500)
	n, _, err := conn.ReadFromUDP(buf)
	if err != nil {
		fmt.Printf("接收消息失败: %v\n", err)
		os.Exit(1)
	}
	fmt.Printf("收到组播消息: %s\n", string(buf[:n]))
}

// getLocalIPv4Addresses 过滤出所有非环回的本地IPv4地址
func getLocalIPv4Addresses() ([]net.IP, error) {
	var ips []net.IP
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return nil, err
	}
	for _, addr := range addrs {
		ipNet, ok := addr.(*net.IPNet)
		if !ok || ipNet.IP.IsLoopback() {
			continue
		}
		ip := ipNet.IP.To4()
		if ip != nil {
			ips = append(ips, ip)
		}
	}
	return ips, nil
}

关键逻辑对应说明

  1. UDP套接字创建与绑定:用net.ListenUDP创建IPv4套接字并绑定到0.0.0.0:multicastPort,对应Python的sock.bind('', MULTICASTPORT)。
  2. 地址复用设置:通过套接字文件描述符调用syscall.SetsockoptInt开启SO_REUSEADDR,对应Python的sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)。
  3. 本地IP获取:通过net.InterfaceAddrs遍历接口地址,过滤出非环回IPv4地址,对应Python的hostinterfaceips。
  4. 组播组加入:构造syscall.IPMreq结构体,调用syscall.SetsockoptIPMreq执行IP_ADD_MEMBERSHIP操作,对应Python的sock.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, ...)。
  5. 消息接收:用conn.ReadFromUDP阻塞接收组播消息,对应Python的sock.recv(1500)。

内容的提问来源于stack exchange,提问作者Anton Lahti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:37:32