Многоадресная привязка Python к фреймворку на конкретном интерфейсе - PullRequest
7 голосов
/ 31 марта 2011

После поиска высоко и низко по Google, я не нашел окончательного ответа на следующий вопрос: примерно следуя следующему руководству: http://twistedmatrix.com/documents/10.2.0/core/howto/udp.html#auto3

Как можно связать витого многоадресного прослушивателя с ТОЛЬКО адресом многоадресной рассылки и на определенных или всех интерфейсах.

Рассматривая реактор.listenMulticast, он не предоставляет абстракцию для аппаратного интерфейса, а только псевдоинтерфейс, представленный IP-адресом. Я не могу найти способ привязки только по многоадресному адресу, например 224.0.0.1 конкретного интерфейса или всех интерфейсов. Кто-нибудь может предоставить дополнительную информацию по этому вопросу?

Ответы [ 3 ]

3 голосов
/ 23 сентября 2012

Другие ответы могут решить проблему, но есть «более извращенный» (и, вероятно, более простой) способ прослушивания многоадресной группы на нескольких интерфейсах.

Прослушивание многоадресной группы наодин или несколько интерфейсов

Чтобы прослушивать многоадресную группу на одном или нескольких интерфейсах, укажите IP-адрес каждого требуемого интерфейса в нескольких вызовах метода transport.joinGroup () протокола в качестве аргумента 'interface'.

Ниже приведен пример, который работает на моем компьютере с Linux и заставит вашу систему прослушивать многоадресные рассылки на определенных интерфейсах.Замените IP-адреса теми, которые принадлежат вашей системе.

#!/usr/bin/env python

from twisted.internet import protocol
from twisted.internet import reactor

class MyProtocol(protocol.DatagramProtocol):
    def startProtocol(self):
        # Join a multicast group, 224.0.0.9, on the interface belonging
        # to each of these IPs.
        # XXX Replace the interface_ips with one or more IP addresses belonging
        # to your system.
        for interface_ip in ["192.168.2.2", "10.99.1.100"]:
            self.transport.joinGroup("224.0.0.9", interface_ip)

if __name__ == "__main__":
    reactor.listenMulticast(1520, MyProtocol())
    reactor.run()

Вы можете проверить, что интерфейс прослушивает новую многоадресную группу, используя команду /sbin/ip maddr show.Найдите желаемое имя интерфейса в выходных данных команды и убедитесь, что под ним отображается многоадресная группа.

Пример UDP-сервера, связанный с исходным сообщением, должен иметь возможность сделать то же самое, изменив вызов на joinGroup.() для включения второго аргумента IP-адреса, как указано выше.

Отправка многоадресных рассылок с определенного IP-адреса

Если вы получаете многоадресные данные в сокете, есть вероятностьВы также захотите отправить многоадресные данные - возможно, из нескольких интерфейсов.Поскольку он тесно связан, и примеров здесь очень мало, я добавлю его сюда.Внутри объекта twisted.internet.protocol.DatagramProtocol вы можете использовать метод self.transport.setOutgoingInterface () для управления исходным IP-адресом, который будет использоваться для последующих вызовов self.transport.write ().Пример, показывающий отправку сообщения с нескольких IP-адресов / интерфейсов:

class MyProtocol(protocol.DatagramProtocol):
    # ...
    def send_stuff(self, msg):
        for src_ip in ["10.0.0.1", "192.168.1.1"]:
            self.transport.setOutgoingInterface(src_ip)
            self.transport.write(msg, ("224.0.0.9", 1520))

Предположим, что эти IP-адреса были назначены двум различным интерфейсам.Нюхнув Wireshark, вы увидите сообщение, отправленное с первого интерфейса, а затем со второго интерфейса, используя каждый IP-адрес в качестве исходного IP-адреса для соответствующей передачи.

3 голосов
/ 01 мая 2011

reactor.listenMulticast возвращает объект twisted.internet.udp.MulticastPort. Этот объект владеет сокетом, который вы слушаете. Так что держитесь за результат реактора.listenMulticast и установите соответствующий параметр сокета (в данном случае он выглядит как SO.BINDTODEVICE) вместе со строкой устройства с нулевым символом в конце.

import IN, socket, struct

udp_port = reactor.listenMulticast(8005, MulticastServerUDP())
dev = "eth0" + "\0"
udp_port.socket.setsockopt(socket.SOL_SOCKET, IN.SO_BINDTODEVICE, dev)
reactor.run()

Было бы неплохо, если бы это было открыто непосредственно через вызов listenMulticast, но при условии, что это сработает, это будет довольно простой патч. Дайте мне знать, если это решит вашу проблему.

1 голос
/ 06 июня 2012

Простой, если неуклюжий подход может состоять в том, чтобы просто указать маршрут через что-то вроде:

sudo route add 239.255.0.0 -interface en0 -netmask 255.255.0.0
...