Python中实现点对点聊天应用服务器,有什么推荐的框架?目前考虑使用tornado

1 需要已读回执功能
2.性能能支持 10W 人同时在线
Python中实现点对点聊天应用服务器,有什么推荐的框架?目前考虑使用tornado

21 回复

或者服务端有没有封装程度更高的库推荐?感谢~


对于点对点聊天应用服务器,Tornado是个不错的选择,它基于事件循环,能高效处理大量并发连接,特别适合长连接的聊天场景。不过,如果你需要更高级的实时通信功能,可以考虑以下几个框架:

  1. Tornado:轻量级、异步,适合自己实现简单的WebSocket聊天。
  2. Socket.IO (Python-SocketIO):基于WebSocket,提供了房间、命名空间等高级功能,更适合复杂的实时应用。
  3. Django Channels:如果你熟悉Django,可以用它构建支持WebSocket的聊天服务器,集成度较高。
  4. aiohttp:异步HTTP和WebSocket框架,适合轻量级的实时通信。

如果你用Tornado,这里是一个简单的点对点聊天服务器示例:

import tornado.ioloop
import tornado.web
import tornado.websocket
import uuid

# 存储所有连接的客户端
clients = {}

class ChatWebSocket(tornado.websocket.WebSocketHandler):
    def open(self):
        # 为每个连接生成唯一ID
        self.client_id = str(uuid.uuid4())
        clients[self.client_id] = self
        print(f"客户端 {self.client_id} 已连接")

    def on_message(self, message):
        # 这里简单地将消息广播给所有其他客户端
        for client_id, client in clients.items():
            if client_id != self.client_id:
                client.write_message(f"客户端 {self.client_id}: {message}")

    def on_close(self):
        if self.client_id in clients:
            del clients[self.client_id]
        print(f"客户端 {self.client_id} 已断开")

def make_app():
    return tornado.web.Application([
        (r"/ws", ChatWebSocket),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    print("聊天服务器运行在 ws://localhost:8888/ws")
    tornado.ioloop.IOLoop.current().start()

这个例子创建了一个WebSocket服务器,客户端连接后可以发送消息,服务器会将消息广播给所有其他客户端。你可以在此基础上扩展,比如添加用户认证、私聊功能(通过client_id定向发送消息)等。

总结:Tornado够用,但根据需求可以考虑更专门的实时框架。

python3 + asyncio 直接用标准库也可以, 用上层封装也 ok https://github.com/timofurrer/awesome-asyncio

这要啥框架,直接 websocket

flask-socketio ?不知道性能怎么样

已读回执只是一种设计方案,和技术实现没有特别的联系。举个例子,用户 A 在当前屏幕看 B 发过来的消息 b1,这个时候 B 又发了一条消息 b2 过来,b2 这条消息算已读?未读?

django channels 最近正好在用 非常爽~

go websocket, 刚写完

前几天看见一个 twes 还是怎么拼写的一个框架,直接有聊天样例,刚刚没有百度到

点对点? P2P ?那要啥服务器

https://cloud.tencent.com/product/im
日活低于 10w 还免费……自己造轮子不知道怎么死的。

twisted https://twistedmatrix.com/trac/ 听说比较稳定,性能可以,我 python3.7 没有安装好,自己技术不行

tornado 管理 10w 连接问题不大,反正都是由系统 epoll 处理的,重点还是在消息发送数量,发送量很大的话会受限 python 语言的性能可能会跟不上,还有可能还是连接建立时认真的过程吧,如果需要重启的话,单个进程 10w 连接建立可能会比较久

flask-socketio 这种可能管理 10w 连接都有问题,更别说转发消息了,socketio 玩具吧,真要用估计还是要自己实现服务端的吧

不过话说 10w 的在线,可能需要多进程多机备份的话,就需要路由功能了吧,只是单进程会不会不稳定

已读也都是一条消息了,都一样,只是不知道你只是需要把这个状态转发给发送方,还是服务器要持久化存储,那么要注意受限 python 语言性能,单进程访问 mysql mongodb 等数据库 rps 都不是太高,im 持久化会是个很大问题

话说干嘛不找个云服务,太费劲了吧,还是有业务要处理?

flask-socketio 的后端也是用 gevent,eventlet,aiohttp 的,管理个 10w 连接不还是用 epoll 能有啥问题

#14 你说的对,区别就是 gevent eventlet 完全屏蔽了上层对协程连接的调度,在大量连接同时运行的时候会产生大量协程在运行,使得等待运行的协程栈太长,很容易产生雪崩的

还有 flask-socketio 只能在连接读写有框架做异步,应用层是很难异步的,并发会受限的

是在线聊天室还是 IM,需要"已读回执"功能,那估计是 IM 吧
造个 IM 的轮子没那么简单,存储方案、消息的可靠 /去重 /有序怎么保证,这些有考虑吗
然后 tornado 官方只有异步 tcp 支持(即 iostream),如果进程里用到同步的 mysql/redis 库这些,单进程 10w 在线是搞不定的,1w 都难

做 IM 很有挑战性的事,我认为也是很有意义的一件事,只有对系统架构、网络、系统内核等等都要有一些了解才能做出一个高可用高性能的 IM 系统。

当时设计参考了 https://github.com/Terry-Mao/goim,简化了 Logic,增加了离线消息持久化,最终性能比毛大佬 bench 差一丢丢,调整内核参数和各级缓存之后,每个用户不到 5K 内存开销,1H1G 的阿里云承载 8 万用户。


消息网关别用 python (当然你有 6 倍以上的硬件预算的话洒洒水啦。

tornado 真不太行,高并发干不过 async,做 web 又不像其他线程模型的框架什么东西都能往里放,放到现在来看更像是教科书级的东西。正好去年我也做了一个 im 项目,调研了下 ws 的实现性能差异。总之 IO 密集型的东西最好还是了解下 go 或者 java,c 之流。

bench i7 2600k 8G
target i7 2600k 8G
-s 客户端数量、每秒 echo1 下、测试 30 秒
同时可以参考下 https://github.com/uNetworking/uWebSockets

tornado

bench -a 0.0.0.0:8888 -s 1000 -i 1 -d 30
Total Sent: 29182 , Total Received: 29182 , Bytes Sent 817096 , Bytes Received: 817096 , Average RTT: 8.147407ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

bench -a 0.0.0.0:8888 -s 2000 -i 1 -d 30
Total Sent: 52960 , Total Received: 52960 , Bytes Sent 1482880 , Bytes Received: 1482880 , Average RTT: 77.962957ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

bench -a 0.0.0.0:8888 -s 4000 -i 1 -d 30
2018/04/14 22:35:58 Total Sent: 48032 , Total Received: 48032 , Bytes Sent 1344896 , Bytes Received: 1344896 , Average RTT: 1.004519955s , Connection Error: 464 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

asynicio

bench -a 0.0.0.0:8888 -s 2000 -i 1 -d 30
Total Sent: 57703 , Total Received: 57703 , Bytes Sent 1615684 , Bytes Received: 1615684 , Average RTT: 11.979018ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

bench -a 0.0.0.0:8888 -s 4000 -i 1 -d 30
Total Sent: 88348 , Total Received: 88348 , Bytes Sent 2473744 , Bytes Received: 2473744 , Average RTT: 90.734413ms , Connection Error: 492 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

gorilla

bench -a 0.0.0.0:8888 -s 8000 -i 1 -d 30
Total Sent: 231759 , Total Received: 231759 , Bytes Sent 6489252 , Bytes Received: 6489252 , Average RTT: 17.459239ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

bench -a 0.0.0.0:8888 -s 16000 -i 1 -d 30
Total Sent: 420935 , Total Received: 420935 , Bytes Sent 11786180 , Bytes Received: 11786180 , Average RTT: 36.99979ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

bench -a 0.0.0.0:8888 -s 20000 -i 1 -d 30
Total Sent: 486466 , Total Received: 486466 , Bytes Sent 13621048 , Bytes Received: 13621048 , Average RTT: 79.126184ms , Connection Error: 1059 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

openresty

bench -a 0.0.0.0:8888 -s 20000 -i 1 -d 30
Total Sent: 559234 , Total Received: 559234 , Bytes Sent 15658552 , Bytes Received: 15658552 , Average RTT: 20.53849ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

bench -a 0.0.0.0:8888 -s 30000 -i 1 -d 30
Total Sent: 485620 , Total Received: 485620 , Bytes Sent 13597360 , Bytes Received: 13597220 , Average RTT: 193.790583ms , Connection Error: 1769 , Write Error: 0 , Read Error: 0 , Message Mismatch: 5

uWebSockets

bench -a 0.0.0.0:8888 -s 20000 -i 1 -d 30
Total Sent: 562872 , Total Received: 562872 , Bytes Sent 15760416 , Bytes Received: 15760416 , Average RTT: 15.233624ms , Connection Error: 0 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0

bench -a 0.0.0.0:8888 -s 30000 -i 1 -d 30
Total Sent: 464767 , Total Received: 464767 , Bytes Sent 13013476 , Bytes Received: 13013476 , Average RTT: 12.200729ms , Connection Error: 13107 , Write Error: 0 , Read Error: 0 , Message Mismatch: 0


python 当然写起来最舒服就是慢! go 则是很好的选择 channel goroutine 语言层面控制力非常给力,openresty 简直让 nginx 为所欲为,lua 写起来也非常非常爽,甚至我还在上面写 api,一旦要做 co 或者 worker 之间 sync、event、lock、share 就有点智障了。。

是不是对“点到点”有什么误解?
你这个叫中心制

#17 tornado 和 asynicio 在高并发下的问题都是同一个,python 语言性能太低,高并发下同时处理大量连接数据会导致协程栈太长,每个 req 处理时间大大增加而导致很多连接会超时,事实上 python 在普通 curd 的 web 场景下大约 64-128 同时处理 req 之间就能保持进程 100%cpu 使用率,既保持每个 req 的低延迟又可以保持每秒吞吐不变,当然是 mysql redis 都用异步的情况下

asynicio 比 tornado 性能高一点点大概是 tornado iostream 的实现问题了,太繁琐,导致性能比 asynicio 的 protocol 性能低了很多

#16 mysql/redis 都有 tornado 的异步版本 driver 啊
redis 推荐 https://github.com/thefab/tornadis 比 tornado-redis 性能高很多
mysql 推荐 https://github.com/snower/TorMySQL

关键是为什么每个 c 端链接就一定要有一个 redis 或者 mysql 呢?你指的是传统的 web 架构吧?这种 im 后端应该是一个 pipeline 或者是一个 watch 机制的实现。


同意,所以我在一般 web 场景用一些同步框架,百 qps 这个量级性能会有一点打折扣但不会差很多,至少写起来不这么难受,第三方库可选择性大了很多。我以前觉得 tornado 也还行,直到被 tornado-redis 不可思议的 rtt 和 tornado-mysql 不可思议的 cpu 坑过以后一直有心理阴影。至于单实例千 qps 可能就不考虑 python 了。

回到顶部