◆何金獅
(福建富士通信息軟件有限公司 福建 350003)
一種基于epoll模型的高效代理服務架構
◆何金獅
(福建富士通信息軟件有限公司 福建 350003)
本文通過對epoll模型的靈活運用,結合多線程多隊列模式,對socket描述符進行合理分配,介紹了一種高效的代理服務框架。
數據轉發;代理服務;epoll
代理服務被用于數據轉發,需要同時管理客戶端和服務器連接,并且能夠準確的將一端的數據轉發到對應的另一端,在連接數大的情況下對性能和穩定性都是一個非常大的考驗。因此一個高效的代理服務框架顯得非常重要。
epoll是Linux內核為處理大批量文件描述符而作了改進的poll,是Linux下多路復用IO接口select/poll的增強版本,它能顯著提高程序在大量并發連接中只有少量活躍的情況下的系統CPU利用率。另一原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入準備隊列的描述符集合就行了。epoll除了提供select/poll那種IO事件的水平觸發(Level Triggered)外,還提供了邊緣觸發(Edge Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少系統調用,提高應用程序效率。
代理服務的主要功能是將一個網絡終端的數據轉發到另一個網絡終端,兩端設備不需要在同一個局域網內,只要網絡可達即可。一個完整的代理服務過程分為,客戶端與代理服務器建立連接,代理服務器根據自定義的代理協議與目標服務器創建連接,客戶端與服務端通訊的所有數據都由代理服務器來轉發。常見的代理服務有HTTP代理和Socks代理。

圖1 網絡拓撲
架構設計的思想是主進程根據系統的cpu核心數創建對應數量的線程,并且為每個線程創建一個隊列。主進程負責監聽新的連接請求,一旦有新的請求進來,主進程會遍歷所有的隊列將新的請求的socket描述符以及相關信息放入數量最小的隊列中。子線程實時掃描隊列發現有新的請求就將請求從隊列中移除并且放入線程內部的epoll隊列中,子線程負責管理這些連接的數據收發。
子線程從對應的隊列中獲取新連接,創建客戶端結構體一同放入本線程創建的epoll隊列中。子線程進行epoll_wait等待事件觸發,如果事件類型是EPOLLIN讀事件同時是客戶端并且首次觸發,根據連接信息獲取客戶端要連接的服務器信息。子線程創建與服務端的連接,同時創建服務器結構體,并且客戶端和服務端的結構體中分別存放對方的信息,這樣當接收到任何一端的數據時都可以快速找到對端的連接。

圖2 主進程流程

圖3 線程流程
將客戶端的連接通過獨立的隊列均衡負載到不同的線程中,由每個獨立的線程分別建立epoll監聽極大的提高了數據處理能力。通過在同一種結構體中用字段表示連接是屬于客戶端還是服務端的方式,在epoll中可以同時對客戶端和服務端連接進行管理使得架構更加靈活高效。
[1]宋敬彬,孫海濱.Linux網絡編程.清華大學出版社,2010.
[2]https://banu.com/blog/2/how-to-use-epoll-a-complet --example-in-c/.