Я пишу приложение для Windows на Python, которому необходимо искать доступные сетевые устройства с помощью ssdp. Поиск будет использоваться для получения IP-адресов определенных типов устройств для установки соединения.
Проблема
Мы получали очень непоследовательный поиск по ssdp. результаты. Иногда это работает, иногда терпит неудачу. Используя Wireshark и Device Sniffer (из инструментов Meshcommander UPnP), мы обнаружили, что в случае сбоя ssdp M-SEARCH отправляется на адрес 127.0.0.1, поэтому он никогда не достигает сети. Кажется, нет никакой закономерности или причины, когда это работает или терпит неудачу. Я уверен, что это характерно для Windows, поскольку тот же код без проблем работает на Mac.
Код, который работает с перерывами:
Код: Выделить всё
import socket
import struct
import time
local_ip = '192.168.20.48'
ssdp_addr = "239.255.255.250"
ssdp_port = 1900
searchterm = 'ssdp:all'
m_msg = f"""\
M-SEARCH * HTTP/1.1\r\n\
Host: {ssdp_addr}:{ssdp_port}\r\n\
Man: "ssdp:discover"\r\n\
ST: {searchterm}\r\n\
MX: 2\r\n\r\n""".encode("utf-8")
if __name__ == "__main__":
# Method 1, occassionally works. Most of the time sends to 127.0.0.1:port
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 5)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.settimeout(5)
sock.sendto(m_msg, (ssdp_addr, ssdp_port)) # Sometimes works, sometimes doesn't...
# If send worked, this will receive the response. But, if send is routed to 127.0.0.1,
# nothing is received (which is expected given it is localhost)
tLim = time.time() + 6
while time.time() < tLim:
try:
data, addr = sock.recvfrom(4096)
print(f"Received from {addr}: {data}")
except socket.timeout:
break
sock.close()
Попытка решения
Я экспериментировал со всеми типами конфигураций Windows, которые только мог придумать (настройки брандмауэра, службы, разрешения, переключение сетей...), но безрезультатно. После поиска в Интернете я нашел метод, при котором отправленное сообщение M-Search больше не направляется на адрес 127.0.0.1, но я не могу получить ответ от устройства! С помощью Wireshark я вижу, что устройство отправляет ответ, но код его не читает. Хотя реализация БУДЕТ обнаруживать случайный трафик ssdp, который происходит в то же время в сети.
Код: Выделить всё
import socket
import struct
import time
local_ip = '192.168.20.48'
ssdp_addr = "239.255.255.250"
ssdp_port = 1900
searchterm = 'ssdp:all'
m_msg = f"""\
M-SEARCH * HTTP/1.1\r\n\
Host: {ssdp_addr}:{ssdp_port}\r\n\
Man: "ssdp:discover"\r\n\
ST: {searchterm}\r\n\
MX: 2\r\n\r\n""".encode("utf-8")
if __name__ == "__main__":
# Method 2
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((local_ip, ssdp_port))
group = socket.inet_aton(ssdp_addr)
mreq = struct.pack('4s4s', group, socket.inet_aton(local_ip))
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
sock.settimeout(5)
ret = sock.sendto(m_msg, (ssdp_addr, ssdp_port))
# CODE to listen for SSDP responses. This finds unrelated network upnp notifies, but
# does not get the response from the device. I can see the response from the device is
# being sent with wireshark
tLim = time.time() + 6
while time.time() < tLim:
try:
data, addr = sock.recvfrom(4096)
print(f"Received from {addr}: {data}")
except socket.timeout:
break
sock.close()
Где 192.168.20.48 = локальный IP-адрес ПК, а 192.168.30.82 = локальный IP-адрес устройства.
Справка
Мне интересно, могу ли я внести изменения в любой из этих методов, чтобы они работали последовательно. Первый метод работает какое-то время, какое-то время. Вторая половина метода работает всегда. Я готов использовать модифицированную версию любого из этих методов или совершенно новую, если я совершенно на неправильном пути.
Подробнее здесь: https://stackoverflow.com/questions/792 ... on-windows