【问题标题】:Ping and Pong in a threaded WebSocket server (Python)线程化 WebSocket 服务器中的 Ping 和 Pong (Python)
【发布时间】:2012-01-16 02:49:44
【问题描述】:

我已经使用lastest websocket spec 在 Python 中编写了一个线程化的 websocket 服务器,并且我试图让它每 x 秒向每个客户端发送一个 ping 请求。我想出的唯一方法是像这样覆盖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 中覆盖的工作原理缺乏了解,或者是因为解决此问题的方法根本上是错误的。有没有更好的方法来做到这一点或让这段代码工作?

【问题讨论】:

    标签: python sockets websocket ping


    【解决方案1】:

    代码不会在任何地方设置属性__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 找到该进程。或者,选择其他端口。

    【讨论】:

    • 但它只是抱怨没有这样的属性:/
    • @Dreen 你能澄清一下吗?如果您发布一个 complete 示例和 precise 错误消息(例如 pastebin.),将会非常有帮助
    • 谢谢 phihag,我设法让它识别出它的属性,但现在显然已经绑定了套接字存在问题 - 请参阅错误消息的问题
    • @Dreen 更新了解决新问题的答案。请注意,您并没有让对象识别它的属性——你设置它们。
    • 感谢您的帮助。代码有点工作,但我意识到这种方法是错误的。对于任何潜在的未来参考,更好的方法是创建一个单独的线程并在客户端连接处启动()它。这是一个示例代码(不完整):pastebin.com/Dr6ARD85
    猜你喜欢
    • 2019-03-16
    • 2020-12-29
    • 2017-04-30
    • 2012-05-22
    • 2016-01-19
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    • 2019-10-19
    相关资源
    最近更新 更多