线程 WebSocket 服务器中的 Ping 和 Pong (Python)
我用 Python 编写了一个线程 websocket 服务器,使用 最新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 中的重写工作原理缺乏了解或者对这个问题采取根本错误的方法。有没有更好的方法来做到这一点或者让这段代码工作?
I've written a threaded websocket server in Python, using the lastest websocket spec and I'm trying to make it send a ping request to every client every x seconds. The only way I came up with to do this is overriding BaseServer.server_forever() like this:
# 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()
Here is the function that constructs the Ping frame, it just puts the timestamp in the contents:
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
Bad things happen when I run this
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
I assume this is down to my lack of understanding of how overriding works in Python or to a fundamentally wrong approach to this problem. Is there a better way to do this or a way to make this code work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这些代码不会在任何地方设置属性
__is_shut_down
和__shutdown_request
。因此,尝试访问它们会失败。在构造函数中创建它们,如下所示:响应更新:
意味着另一个进程已经绑定到指定端口。在 Unix 上,您可以使用 sudo netstat -ltpn 找到该进程。或者,选择不同的端口。
The codes does not set the properties
__is_shut_down
and__shutdown_request
anywhere. Therefore, trying to access them fails. Create them in the constructor, like this:In response to the update:
means that another process has already bound to the specified port. On Unix, you can find that process with
sudo netstat -ltpn
. Alternatively, choose a different port.