2017-06-21 59 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