![](/img/trans.png)
[英]Raspberry Pi Python - Multicasting UDP using Socket not working on local network
[英]How to select a network interface for multicasting with python
我正在使用此代码通过 Wlan 网络使用我的设备无线 IP 地址多播一条消息:
import socket
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 5007
IP=''
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 1))
IP = s.getsockname()[0]
print(IP)
s.close()
except:
print("Could not get IP")
s.close()
try:
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
udp_socket.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
udp_socket.sendto(IP, (MCAST_GRP, MCAST_PORT))
udp_socket.close()
print("Multicast Message sent.")
except:
print("Message not sent")
udp_socket.close()
所有设备都通过无线路由器连接,路由器允许多播消息。 该代码正在获取设备的 IP 并在多播消息中发送它。 这些设备混合使用 Linux Debian 8 和 Windows 10 操作系统。
在设备中,唯一的活动网络接口是无线的,这可以立即生效。 问题是有时有多个可用的活动网络接口,如果可用,我需要选择无线接口。 我试图减少无线接口的度量参数的值并且它起作用了,但是我必须手动执行此操作并且我需要它自动化。
我想知道如何补充我的代码,以便能够选择所需的网络接口(希望以可移植的方式)、多播消息并接收它们。 提前致谢。
在连接之前从所需接口绑定到 IP 似乎对大多数人都有效。 诀窍是获得该IP。 打开套接字时 Python 可以选择什么网络适配器的更多详细信息?
您可以尝试使用以下脚本检索 IPv4/IPv6 网络接口的信息。 希望这会有所帮助。
# -*- coding: utf-8 -*-
from ctypes import *
from sys import platform
from socket import AF_INET, AF_INET6, inet_ntop
try:
from socket import AF_PACKET
except ImportError:
AF_PACKET = -1
if platform.startswith("darwin") or platform.startswith("freebsd"):
AF_LINK = 18
IFT_ETHER = 0x6
else:
AF_LINK = -1
IFT_ETHER = -1
def get_if_addresses():
"""
Retrieve all relevant information of IPv4/IPv6 network interfaces.
Based on http://pastebin.com/wxjai3Mw (Author unknown)
"""
# getifaddr structs
class ifa_ifu_u(Union):
_fields_ = [
("ifu_broadaddr", c_void_p),
("ifu_dstaddr", c_void_p)
]
class ifaddrs(Structure):
_fields_ = [
("ifa_next", c_void_p),
("ifa_name", c_char_p),
("ifa_flags", c_uint),
("ifa_addr", c_void_p),
("ifa_netmask", c_void_p),
("ifa_ifu", ifa_ifu_u),
("ifa_data", c_void_p)
]
# AF_UNKNOWN / generic
if platform.startswith("darwin") or platform.startswith("freebsd"):
class sockaddr(Structure):
_fields_ = [
("sa_len", c_uint8),
("sa_family", c_uint8),
("sa_data", (c_uint8 * 14))
]
else:
class sockaddr(Structure):
_fields_ = [
("sa_family", c_uint16),
("sa_data", (c_uint8 * 14))
]
# AF_INET / IPv4
class in_addr(Union):
_fields_ = [
("s_addr", c_uint32),
]
if platform.startswith("darwin") or platform.startswith("freebsd"):
class sockaddr_in(Structure):
_fields_ = [
("sin_len", c_uint8),
("sin_family", c_uint8),
("sin_port", c_ushort),
("sin_addr", in_addr),
("sin_zero", (c_char * 8)) # padding
]
else:
class sockaddr_in(Structure):
_fields_ = [
("sin_family", c_short),
("sin_port", c_ushort),
("sin_addr", in_addr),
("sin_zero", (c_char * 8)) # padding
]
# AF_INET6 / IPv6
class in6_u(Union):
_fields_ = [
("u6_addr8", (c_uint8 * 16)),
("u6_addr16", (c_uint16 * 8)),
("u6_addr32", (c_uint32 * 4))
]
class in6_addr(Union):
_fields_ = [
("in6_u", in6_u),
]
if platform.startswith("darwin") or platform.startswith("freebsd"):
class sockaddr_in6(Structure):
_fields_ = [
("sin6_len", c_uint8),
("sin6_family", c_uint8),
("sin6_port", c_ushort),
("sin6_flowinfo", c_uint32),
("sin6_addr", in6_addr),
("sin6_scope_id", c_uint32),
]
else:
class sockaddr_in6(Structure):
_fields_ = [
("sin6_family", c_short),
("sin6_port", c_ushort),
("sin6_flowinfo", c_uint32),
("sin6_addr", in6_addr),
("sin6_scope_id", c_uint32),
]
# AF_PACKET / Linux
class sockaddr_ll(Structure):
_fields_ = [
("sll_family", c_uint16),
("sll_protocol", c_uint16),
("sll_ifindex", c_uint32),
("sll_hatype", c_uint16),
("sll_pktype", c_uint8),
("sll_halen", c_uint8),
("sll_addr", (c_uint8 * 8))
]
# AF_LINK / BSD|OSX
class sockaddr_dl(Structure):
_fields_ = [
("sdl_len", c_uint8),
("sdl_family", c_uint8),
("sdl_index", c_uint16),
("sdl_type", c_uint8),
("sdl_nlen", c_uint8),
("sdl_alen", c_uint8),
("sdl_slen", c_uint8),
("sdl_data", (c_uint8 * 46))
]
if platform.startswith("darwin"):
libc = CDLL("libSystem.dylib")
elif platform.startswith("freebsd"):
libc = CDLL("libc.so")
else:
libc = CDLL("libc.so.6")
ptr = c_void_p(None)
result = libc.getifaddrs(pointer(ptr))
if result:
return None
ifa = ifaddrs.from_address(ptr.value)
result = []
while ifa:
# Python 2 gives us a string, Python 3 an array of bytes
if type(ifa.ifa_name) is str:
name = ifa.ifa_name
else:
name = ifa.ifa_name.decode()
if ifa.ifa_addr:
sa = sockaddr.from_address(ifa.ifa_addr)
data = {}
if sa.sa_family == AF_INET:
if ifa.ifa_addr is not None:
si = sockaddr_in.from_address(ifa.ifa_addr)
data['addr'] = inet_ntop(AF_INET, si.sin_addr)
if ifa.ifa_netmask is not None:
si = sockaddr_in.from_address(ifa.ifa_netmask)
data['netmask'] = inet_ntop(AF_INET, si.sin_addr)
# check if a valid broadcast address is set and retrieve it
# 0x2 == IFF_BROADCAST
if ifa.ifa_flags & 0x2:
si = sockaddr_in.from_address(ifa.ifa_ifu.ifu_broadaddr)
data['broadcast'] = inet_ntop(AF_INET, si.sin_addr)
if sa.sa_family == AF_INET6:
if ifa.ifa_addr is not None:
si = sockaddr_in6.from_address(ifa.ifa_addr)
data['addr'] = inet_ntop(AF_INET6, si.sin6_addr)
if data['addr'].startswith('fe80:'):
data['scope'] = si.sin6_scope_id
if ifa.ifa_netmask is not None:
si = sockaddr_in6.from_address(ifa.ifa_netmask)
data['netmask'] = inet_ntop(AF_INET6, si.sin6_addr)
if sa.sa_family == AF_PACKET:
if ifa.ifa_addr is not None:
si = sockaddr_ll.from_address(ifa.ifa_addr)
addr = ""
total = 0
for i in range(si.sll_halen):
total += si.sll_addr[i]
addr += "%02x:" % si.sll_addr[i]
addr = addr[:-1]
if total > 0:
data['addr'] = addr
if sa.sa_family == AF_LINK:
dl = sockaddr_dl.from_address(ifa.ifa_addr)
if dl.sdl_type == IFT_ETHER:
addr = ""
for i in range(dl.sdl_alen):
addr += "%02x:" % dl.sdl_data[dl.sdl_nlen + i]
addr = addr[:-1]
data['addr'] = addr
if len(data) > 0:
iface = {}
for interface in result:
if name in interface.keys():
iface = interface
break
if iface:
iface[name][sa.sa_family] = data
else:
iface[name] = { sa.sa_family : data }
result.append(iface)
if ifa.ifa_next:
ifa = ifaddrs.from_address(ifa.ifa_next)
else:
break
libc.freeifaddrs(ptr)
return result
在 Linux Debian 8 和 Windows 10 中测试使用 Python 2.7。
对于 Linux:
def get_local_wireless_ip_linux():
import fcntl
import struct
import socket
ifname = 'wlan0'
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
wlan0_ip = (socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24]))
return wlan0_ip
对于 Windows:
def get_local_wireless_ip_windows():
import subprocess
arp = subprocess.check_output('arp -a')
local_ipv4 = []
for line in arp.split('\n'):
if 'Interface' in line:
local_ipv4.append(line.split(':')[1].split('---')[0].strip())
return local_ipv4[-1]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.