Сокет Pythons, recvfrom() не работает на Rasperry Pi

#python #sockets

#python #сокеты

Вопрос:

Я хочу связаться с узлом Art-Net (это сетевое устройство для преобразования пакетов UDP Art-Net в DMX-выход, который используется при освещении сцены и фильмов) с помощью raspberry pi, работающего на python на raspbian.

С этим кодом ниже есть 2 проблемы, одна из которых связана с pi: при запуске кода на моем компьютере с Windows все работает нормально. При выполнении того же кода (за исключением изменения IP-адреса для socket.bind) код отправляет пакеты ArtPoll, узел в сети отвечает ArtPollReply, но эти пакеты не принимаются скриптом python. Код зависает на строке «data, addr = self.sock.recvfrom (4096)», но ничего не требуется для получения (есть пакеты для получения, компьютер получает эти пакеты одновременно).

Конфигурация сети в порядке, я все проверил. Я проверил также другую вещь artnet python, которая сработала — так что с самим сетевым интерфейсом проблем нет.

Вот весь демонстрационный код, который должен продемонстрировать проблему.

 import socket
import struct
import threading
import time

class PollThread(threading.Thread):      
def __init__(self, artnet):
    threading.Thread.__init__(self)
    self.artnet = artnet

def run(self):
    while self.artnet.running:
        #break
        time.sleep(3)
        print self.artnet.nodes_ip
        self.artnet.ArtPoll()
    print "EXIT POLL THREAD"

class ArtNet(threading.Thread):
    nodes_ip = []
    nodes_data = []
    running = True
    def __init__(self):
        threading.Thread.__init__(self)
        self.pollthread = PollThread(self)
        ip = "10.0.0.2"
        self.header_artpoll = self.set_Header_ArtPoll()
        #open socket
        try:      
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)                    
        except socket.error, msg:
            print 'Failed to create socket. Error code: '   str(msg[0])   ' , Error message : '   msg[1]
        print '[INFO] Socket Created %s' % ip
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)         #Enable Broadcast
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)         #Diable Port blocking when reuse this port
        self.sock.bind((ip, 6454))

    def run(self):
        self.pollthread.start()
        while self.running:
            print "RECEIVING...."
            data, addr = self.sock.recvfrom(4096)
            print "RECEIVED DATA!"
            print addr
            opcode = struct.unpack('<H', data[8:10])[0]
            if opcode == 0x2000:
                self.HandleArtPollReply(addr[0], data)
                #self.artnet_handler.ArtPollReply() 
            if opcode == 0x2100:
                self.HandleArtPollReply(addr[0], data)
        print "EXIT ARTNET THREAD"

    def set_Header_ArtPoll(self):
        header = []
       header.append("Art-Netx00")                                        #ID
        header.append(struct.pack('<H', 0x2000))                            #OpCode
        header.append(struct.pack('>H', 14))                                #ProtVer
        header.append(struct.pack('>H', 0b00000000))                        #TalkToMe
        header.append(chr(0xe0))                                            #Priority
        header = "".join(header)
        return header

    def HandleArtPollReply(self, ip, data):
        self.nodes_ip.append(ip)
        self.nodes_data.append(data)

    def ArtPoll(self):         
        self.nodes_ip = []
        self.nodes_data = []
        self.sock.sendto(self.header_artpoll, ('<broadcast>', 6454))
        self.sock.sendto(self.header_artpoll, ('10.255.255.255', 6454))
        self.sock.sendto(self.header_artpoll, ('2.255.255.255', 6454))

if __name__ == '__main__':
    artnet = ArtNet()
    artnet.start()
    s = raw_input()
    artnet.sock.close()
    artnet.running = False
    print "MIAN EXIT"
  

Редактировать:
Теперь у меня есть дополнительная информация: если я привязываюсь к «, все работает нормально, также на pi.

 self.sock.bind(('', 6454))
  

В комментариях я получил совет использовать

 self.sock.bind((socket.INADDR_ANY, 6454))
  

Это выдает ошибку:

 self.sock.bind((socket.INADDR_ANY, 6454))
File "C:Python27libsocket.py", line 228, in meth
return getattr(self._sock,name)(*args)
TypeError: coercing to Unicode: need string or buffer, int found
  

Это работает для меня при первом запуске, но может быть, мне приходится использовать несколько интерфейсов в системе для разных задач — поэтому я могу использовать привязку к интерфейсу на основе ip, чтобы различать предоставляемые ими услуги.
РЕДАКТИРОВАТЬ КОНЕЦ

Вторая проблема в том, что я не знаю, как закрыть класс ArtNet (), потому что, когда я это делаю, поток зависает на «data, addr = self.sock.recvfrom (4096)» в ожидании данных. Поэтому я должен прервать эту команду. Моя идея состоит в том, чтобы отправить некоторые данные на компьютер, чтобы разблокировать эту вещь….

РЕДАКТИРОВАТЬ: я уже использую этот self.sock.close(), и поток продолжает выполняться после close()

Комментарии:

1. Что касается последней проблемы …. добавьте close метод в класс, который закрывает сокет, и пусть все, что решит завершить вызов, завершит его. Закрытие должно выдать ошибку recvfrom .

2. Если у вас нет очень веской причины, вы должны привязаться к INADDR_ANY вместо определенного IP-адреса. Это избавит вас от необходимости что-то менять при перемещении между компьютерами. Единственный раз, когда вы захотите указать IP-адрес, — это когда вы хотите выполнить какую-то маршрутизацию по разным сетям.