關於 python gevent 架框 作為 TCP伺服器 的 代碼問題 , 每個 socket 的 消息 接收 是否有使用 事件監聽回調的方法呢?
12-29
關於 python gevent TCP伺服器的問題,關於 TCPServer , 每個 客戶端 連接到 TCPServer 時 gevent 會自動分配一個 greenlet 執行 ,可是 如何 監聽 每一個 sokcet 客戶端的消息 接收呢, 看到的 代碼是 在 greenlet 方法里 運用 循環 接收,難道沒有 回調嗎? 如圖
gevent 比起其他框架(比如tornado,twisted)的一個巨大優勢就是:用同步的方法(自然沒有回調函數)寫非同步應用,因為同步的方式更接近開發人員的編程思維。
gevent可以用一句話向pythoner闡述:使用多路IO復用對文件描述符的事件監聽,從而撬動協程的「透明」切換。這句話說起來容易,但是闡述起來就複雜些:
- 底層(或者說主協程)自然有一個多路IO復用循環(linux上是epoll,unix是kqueue,以下統一用epoll代替描述)
- 當處理一個socket鏈接時,就創建一個協程greenlet去處理。
- 當socket遇到阻塞的時候,比如等待數據的返回或者發送,此時gevent做了很關鍵的兩步:
- 為這個socket的fd在epoll上添加可讀或者可寫事件回調,而這個回調函數便是 gevent.getcurrent().switch
- 通過 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模塊,做了以下修改:
- 將所有的socket設置成非阻塞。
- 修改關鍵函數,比如send,recv,發生阻塞(捕獲到異常 EWOULDBLOCK)時,在socket的fd添加回調函數,並跳回到主協程。
ps,給python socket打patch,固然好,但是有個小缺點,就是:python c擴展模塊中的socket並不受gevent的管制和調度,因此用在gevent中的網路庫,都盡量使用純python庫。
這裡這個循環是驅動一個客戶端的整個會話的循環。整個 echo 都是當有客戶連接到 StreamServer 監聽埠之後,被當作回調,放在一個 greenlet 里執行的。
推薦閱讀:
※如何學習 TCP/IP 協議?
※在TCP的四次分手當中,被動關閉方是如何知道數據已經接收完了?
※DNS解析的過程是什麼,求詳細的?
※《tcp/ip詳解》三卷本該怎麼看?
※為什麼整個127.*網段都被拿來當做環回地址了?