Ping и Pong в поточном сервере WebSocket (Python) - PullRequest
1 голос
/ 08 декабря 2011

Я написал многопоточный сервер веб-сокетов на Python, используя последнюю спецификацию веб-сокетов , и я пытаюсь заставить его отправлять запрос ping каждому клиенту каждые x секунд. Единственный способ сделать это - переопределить BaseServer.server_forever () следующим образом:

# override BaseServer's serve_forever to send a ping request every now and then
class ModTCPServer(SocketServer.TCPServer):
    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
        SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
        self.__is_shut_down = threading.Event()
        self.__shutdown_request = False

    def serve_forever(self, poll_interval=0.5):
        ###
        global PING_EVERY_SEC
        self.lastPing = int(time())
        ###
        self.__is_shut_down.clear()
        try:
            while not self.__shutdown_request:
                r, w, e = select.select([self], [], [], poll_interval)
                if self in r:
                    self._handle_request_noblock()
                ###
                now = int(time())
                if (now - self.lastPing) >= PING_EVERY_SEC:
                    self.socket.send(WebSocketPing(['0x89','0x21','0xa7','0x4b'], now)) # arbitrary key
                    self.lastPing = now
                ###
        finally:
            self.__shutdown_request = False
            self.__is_shut_down.set()

class LoginServer(SocketServer.ThreadingMixIn, ModTCPServer):
    pass

server = LoginServer(("", PORT), ApplicationHandler)
print "serving at port", PORT

server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()

while server_thread.isAlive():
    pass

server.shutdown()

Вот функция, которая создает кадр Ping, она просто помещает отметку времени в содержимое:

def WebSocketPing(key, timestamp=False):
    data = ['0x89','0x8a'] # 0x89 = fin,ping 0x8a = masked,len=10
    data.extend(key)
    if timestamp:
        t = str(timestamp)
    else:
        t = str(int(time()))
    for i in range(10):
        masking_byte = int(key[i%4],16)
        masked = ord(t[i])
        data.append(hex(masked ^ masking_byte))
    frame = ''
    for i in range(len(data)):
        frame += chr(int(data[i],16))
    return frame

Плохие вещи случаются, когда я запускаю это

Traceback (most recent call last):
  File "LoginServer.py", line 91, in <module>
    server = LoginServer(("", PORT), ApplicationHandler)
  File "LoginServer.py", line 63, in __init__
    SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
  File "/usr/lib/python2.6/SocketServer.py", line 400, in __init__
    self.server_bind()
  File "/usr/lib/python2.6/SocketServer.py", line 411, in server_bind
    self.socket.bind(self.server_address)
  File "<string>", line 1, in bind
socket.error: [Errno 112] Address already in use

Я предполагаю, что это связано с моим непониманием того, как переопределение работает в Python, или с принципиально неправильным подходом к этой проблеме. Есть ли лучший способ сделать это или способ заставить этот код работать?

1 Ответ

3 голосов
/ 08 декабря 2011

Коды нигде не устанавливают свойства __is_shut_down и __shutdown_request.Поэтому попытка доступа к ним не удалась.Создайте их в конструкторе, например:

class ModTCPServer(SocketServer.TCPServer):
    def __init__(self, *args, **kwargs):
        SocketServer.TCPServer.__init__(self, *args, **kwargs)
        self.__is_shut_down = threading.Event()
        self.__shutdown_request = threading.Event()

В ответ на обновление:

socket.error: [Errno 112] Address already in use

означает, что другой процесс уже связан с указанным портом.В Unix вы можете найти этот процесс с sudo netstat -ltpn.Также можно выбрать другой порт.

...