欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

关于 python gevent 架框 作为 TCP服务器 的 代码问题 , 每个 socket 的 消息 接收 是否有使用 事件监听回调的方法呢?

程序员文章站 2024-01-22 13:41:34
...
关于 python gevent TCP服务器的问题,关于 TCPServer , 每个 客户端 连接到 TCPServer 时 gevent 会自动分配一个 greenlet 执行 ,可是 如何 监听 每一个 sokcet 客户端的消息 接收呢, 看到的 代码是 在 greenlet 方法里 运用 循环 接收,难道没有 回调吗? 如图

关于 python gevent 架框  作为 TCP服务器 的 代码问题  , 每个 socket 的 消息 接收 是否有使用 事件监听回调的方法呢?

回复内容:

gevent 比起其他框架(比如tornado,twisted)的一个巨大优势就是:用同步的方法(自然没有回调函数)写异步应用,因为同步的方式更接近开发人员的编程思维。
gevent可以用一句话向pythoner阐述:使用多路IO复用对文件描述符的事件监听,从而撬动协程的“透明”切换。这句话说起来容易,但是阐述起来就复杂些:
  1. 底层(或者说主协程)自然有一个多路IO复用循环(linux上是epoll,unix是kqueue,以下统一用epoll代替描述)
  2. 当处理一个socket链接时,就创建一个协程greenlet去处理。
  3. 当socket遇到阻塞的时候,比如等待数据的返回或者发送,此时gevent做了很关键的两步:
    1. 为这个socket的fd在epoll上添加可读或者可写事件回调,而这个回调函数便是 gevent.getcurrent().switch
    2. 通过 get_hub().switch() 切换到主协程。切换回主协程,去干其他事情了。但是当该socket可读或者可写,epoll自然会调用上述添加的回调函数,从而切换回socket的处理协程,从上次悬挂点接着往下执行。
之所以做到透明,是因为python socket上打了patch。所谓打patch,就是自己实现了一个socket模块替换了python的标准socket模块。
def patch_socket():
from gevent import socket
_socket = __import__('socket')
_socket.socket = socket.socket
...
gevent实现的socket模块,比起python的标准socket模块,做了以下修改:
  1. 将所有的socket设置成非阻塞。
  2. 修改关键函数,比如send,recv,发生阻塞(捕获到异常 EWOULDBLOCK)时,在socket的fd添加回调函数,并跳回到主协程。
关于 python gevent 架框  作为 TCP服务器 的 代码问题  , 每个 socket 的 消息 接收 是否有使用 事件监听回调的方法呢?
综上所述,gevent不是没有事件监听回调,而是通过给python socket打patch,使其透明化,最终达到让编程人员用同步的思维去开发。
ps,给python socket打patch,固然好,但是有个小缺点,就是:python c扩展模块中的socket并不受gevent的管制和调度,因此用在gevent中的网络库,都尽量使用纯python库。 这里这个循环是驱动一个客户端的整个会话的循环。整个 echo 都是当有客户连接到 StreamServer 监听端口之后,被当作回调,放在一个 greenlet 里执行的。