Python
实现 websocket
服务很简单,有很多的三方包可以用,我从网上大概找到三种常用的包:websocket
、websockets
、Flask-Sockets
。
但这些包很多都“年久失修”, 比如 websocket
在 2010
年就不维护了。
而 Flask-Sockets
也在 2016
年停止维护。
这也给我们提了一个醒,用三方包的时候一定要看下这个包是否还在持续维护,如果作者已经停止了维护,那就坚决不要再用了,因为过不了多久你就会吃个大亏的。
websockets
排除了两个已经不维护的包,现在只剩下一个 websockets
了,那么这个包会满足我们的需求吗?
首先看了下 websockets
,发现社区最近还在维护,而且 websockets
还有完整的源码和使用教程,对新手非常友好。
源码和教程地址:
https://pypi.org/project/websockets/
https://github.com/python-websockets/websockets
https://websockets.readthedocs.io/en/stable/intro/tutorial1.html
示例:
service.py
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import asyncio
import websockets
async def hello(websocket):
recv_data = await websocket.recv()
print('<<< %s' % recv_data)
send_data = 'Hello %s' % recv_data
await websocket.send(send_data)
print('>>> %s' % send_data)
async def start():
print('Server started ...')
async with websockets.serve(hello, '0.0.0.0', 8765):
await asyncio.Future()
if __name__ == '__main__':
asyncio.run(start())
client.py
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import asyncio
import websockets
async def hello():
uri = 'ws://0.0.0.0:8765'
async with websockets.connect(uri) as websocket:
send_data = input("What's your name: ")
await websocket.send(send_data)
print('>>> %s' % send_data)
recv_data = await websocket.recv()
print('<<< %s' % recv_data)
if __name__ == '__main__':
asyncio.run(hello())
这样就是个简单的 WebSocket
服务器/客户端程序了,也是 WebSocket
中最核心的东西了。
运行结果:
但是这样有一个问题,服务器在收到一条消息之后就关闭连接,如果想实现持久连接就需要用到循环来处理了。
async with websockets.connect(uri) as websocket:
for i in range(10):
send_data = input("What's your name: ")
...
如果用到异步需要加上 async
:
async def handler(websocket):
async for message in websocket:
print(message)
有时候可能还会出现一次只能有一个客户端连接的问题,一般来说,这是程序中时间的调用没有使用异步导致。
例如,此连接处理程序可阻止事件循环在一秒钟内运行:
async def handler(websocket):
time.sleep(1)
...
将其更改为:
async def handler(websocket):
await asyncio.sleep(1)
...
如何开启多进程?
如果想开启多进程,可以用 Python
自带的包实现,先导入进程池模块,然后启动所有进程,多进程用法参考 Python3 多进程编程 这篇文章。
from multiprocessing import Pool
...
def main():
asyncio.run(start())
if __name__ == '__main__':
p = Pool(30)
for i in range(10):
p.apply_async(main)
p.close()
p.join()
...
更多技巧和常见问题请参考:https://websockets.readthedocs.io/en/stable/faq/server.html