Я использую, многоадресно передает UDP по localhost для реализации свободного набора совместных программ, работающих на единственной машине. Следующий код работает хорошо над MAC OSX, Windows и Linux. Дефект - то, что код получит пакеты UDP за пределами localhost сети также. Например, sendSock.sendto(pkt, ('192.168.0.25', 1600))
получен моей тестовой машиной при отправке от другого поля в моей сети.
import platform, time, socket, select
addr = ("239.255.2.9", 1600)
sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 24)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF,
socket.inet_aton("127.0.0.1"))
recvSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
if hasattr(socket, 'SO_REUSEPORT'):
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
recvSock.bind(("0.0.0.0", addr[1]))
status = recvSock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(addr[0]) + socket.inet_aton("127.0.0.1"));
while 1:
pkt = "Hello host: {1} time: {0}".format(time.ctime(), platform.node())
print "SEND to: {0} data: {1}".format(addr, pkt)
r = sendSock.sendto(pkt, addr)
while select.select([recvSock], [], [], 0)[0]:
data, fromAddr = recvSock.recvfrom(1024)
print "RECV from: {0} data: {1}".format(fromAddr, data)
time.sleep(2)
Я попытался recvSock.bind(("127.0.0.1", addr[1]))
, но это препятствует тому, чтобы сокет получил любой многоадресный трафик. Существует ли надлежащий способ настроить recvSock, чтобы только принять многоадресные пакеты из 127/24 сети, или я должен протестировать адрес каждого полученного пакета?
К сожалению, многоадресный IP не имеет такой функции «фильтрации по подсети» - так что, если вы не хотите использовать IPTables (в Linux) или эквивалентный «межсетевой экран» SW / HW вашей системы / сети, чтобы попробовать и «бросайте на пол» каждый многоадресный пакет, который вам не нравится, я думаю, вам придется делать это на уровне приложения (например, с тестом на fromAddr
в вашем внутреннем цикле). Неужели IP-трафик с других хостов настолько велик, что снижает вашу производительность ...?
Вы можете использовать connect()
к 127.0.0.1 на многоадресном сокете, тогда IP-стек сможет фильтровать за вас.
Обновлено с исходным кодом для демонстрации
Вы можете запустить этот сценарий несколько раз на одном хосте и посмотреть, как распределяются многоадресные пакеты:
#!/usr/bin/python
import platform, time, socket, select
addr = ("239.255.2.9", 1600)
sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 24)
sendSock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF,
socket.inet_aton("127.0.0.1"))
recvSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
if hasattr(socket, 'SO_REUSEPORT'):
recvSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
recvSock.bind(("0.0.0.0", addr[1]))
status = recvSock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP,
socket.inet_aton(addr[0]) + socket.inet_aton("127.0.0.1"));
sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
if hasattr(socket, 'SO_REUSEPORT'):
sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, True)
sendSock.bind(("127.0.0.1", addr[1]));
recvSock.connect(("127.0.0.1", addr[1]));
while 1:
pkt = "Hello host: {1} time: {0}".format(time.ctime(), platform.node())
print "SEND to: {0} data: {1}".format(addr, pkt)
r = sendSock.sendto(pkt, addr)
while select.select([recvSock], [], [], 0)[0]:
data, fromAddr = recvSock.recvfrom(1024)
print "RECV from: {0} data: {1}".format(fromAddr, data)
time.sleep(2)
Чтобы инициировать пакеты с другого интерфейса:
#!/usr/bin/python
import platform, time, socket, select
sendSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
pkt = "Hello from network.";
sendSock.sendto(pkt, ('10.65.42.129', 1600))
Я запустил все три сценария на Cygwin под Windows XP и убедился, что результат соответствует требованиям.
Пример вывода
SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:15 2013
RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:14 2013
RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:15 2013
SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:17 2013
RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:16 2013
RECV from: ('127.0.0.1', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:15:17 2013
Ранее вывод показывал внешние пакеты, например:
SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:05 2013
RECV from: ('10.65.42.129', 4711) data: Hello from network.
RECV from: ('127.0.0.1', 4710) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:05 2013
SEND to: ('239.255.2.9', 1600) data: Hello host: NYCMDV8X5R1 time: Thu Feb 21 13:07:11 2013
RECV from: ('10.65.42.129', 4712) data: Hello from network.