2017-06-21 57 views
1

多播我使用这个代码多播消息与我的设备通过WLAN网络的无线IP地址:如何选择网络接口,用于与Python

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 OS。

在设备是唯一有效的网络接口是无线的,这是直接工作。问题是,有时会有多个活动网络接口可用,并且我需要选择无线网络接口(如果有)。我试图减少无线接口的度量参数的值,它工作,但我不得不手动这样做,我需要它自动化。

IP metric values.

我想知道怎样来弥补我的代码,可以选择所需的网络接口(希望在便携式的方式),组播报文和接收他们。提前致谢。

回答

1

在连接之前绑定到来自所需接口的IP似乎最适用。诀窍是获得IP。 在 Can Python select what network adapter when opening a socket?

而且How can I get the IP address of eth0 in Python?

+0

谢谢你带领我走向正确的方向。获取所需接口的IP地址在Windows和Linux中,我使用了Windows接口的绑定选项,以及Linux接口的SO_BINDTODEVICE(它需要su或sudo权限才能执行)。所有人现在都在工作,通过所需的接口在所需的IP中发送和接收多播消息。 – Towerss

0

进一步的细节可以尝试检索与下面的脚本中你的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