Socket 编程概述
前言
Linux Socket 編程領域,為了處理大量連接請求場景,需要使用非阻塞 I/O 和復用。select、poll 和 epoll 是 Linux API 提供的 I/O 復用方式,自從 Linux 2.6 中加入了 epoll 之后,高性能服務器領域得到廣泛的應用,現在比較出名的 Nginx 就是使用 epoll 來實現 I/O 復用支持高并發,目前在高并發的場景下,Nginx 越來越收到歡迎。
據 w3techs 在 2015 年 8 月 10 日的統計數據表明,在全球 Top 1000 的網站中,有 43.7% 的網站在使用 Nginx,這使得 Nginx 超越了 Apache,成為了高流量網站最信任的 Web 服務器足足有兩年時間。已經確定在使用 Nginx 的站點有:Wikipedia,WordPress,Reddit,Tumblr,Pinterest,Dropbox,Slideshare,Stackexchange 等,可以持續羅列好幾個小時,他們太多了。
下圖是統計數據:
select 模型
下面是 select 函數接口:
int select (int n, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);<br>
select 函數監視的文件描述符分 3 類,分別是 writefds、readfds 和 exceptfds。調用后 select 函數會阻塞,直到有描述符就緒(有數據 可讀、可寫、或者有 except),或者超時(timeout 指定等待時間,如果立即返回設為 null 即可)。當 select 函數返回后,通過遍歷 fd_set,來找到就緒的描述符。
select 目前幾乎在所有的平臺上支持,其良好跨平臺支持是它的一大優點。select 的一個缺點在于單個進程能夠監視的文件描述符的數量存在最大限制,在 Linux 上一般為 1024,可以通過修改宏定義甚至重新編譯內核的方式提升這一限制,但是這樣也會造成效率的降低。
poll 模型
int poll (struct pollfd *fds, unsigned int nfds, int timeout);<br>
不同于 select 使用三個位圖來表示三個 fdset 的方式,poll 使用一個 pollfd 的指針實現。
<br>
pollfd 結構包含了要監視的 event 和發生的 event,不再使用 select “參數-值”傳遞的方式。同時,pollfd 并沒有最大數量限制(但是數量過大后性能也是會下降)。和 select 函數一樣,poll 返回后,需要輪詢 pollfd 來獲取就緒的描述符。
從上面看,select 和 poll 都需要在返回后,通過遍歷文件描述符來獲取已經就緒的 socket。事實上,同時連接的大量客戶端在一時刻可能只有很少的處于就緒狀態,因此隨著監視的描述符數量的增長,其效率也會線性下降。
epoll 模型
epoll 的接口如下:
int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);typedef union epoll_data {void *ptr;int fd;__uint32_t u32;__uint64_t u64;} epoll_data_t;struct epoll_event {__uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */};int epoll_wait(int epfd, struct epoll_event * events,int maxevents, int timeout);<br>
主要是 epoll_create,epoll_ctl 和 epoll_wait 三個函數。epoll_create 函數創建 epoll 文件描述符,參數 size 并不是限制了 epoll 所能監聽的描述符最大個數,只是對內核初始分配內部數據結構的一個建議。epoll_ctl 完成對指定描述符 fd 執行 op 操作控制,event 是與 fd 關聯的監聽事件。op 操作有三種:添加 EPOLL_CTL_ADD,刪除 EPOLL_CTL_DEL,修改 EPOLL_CTL_MOD。分別添加、刪除和修改對 fd 的監聽事件。epoll_wait 等待 epfd 上的 IO 事件,最多返回 maxevents 個事件。
在 select/poll 中,進程只有在調用一定的方法后,內核才對所有監視的文件描述符進行掃描,而 epoll 事先通過 epoll_ctl() 來注冊一個文件描述符,一旦基于某個文件描述符就緒時,內核會采用類似 callback 的回調機制,迅速激活這個文件描述符,當進程調用 epoll_wait 時便得到通知。
epoll 的優點主要是一下幾個方面:
1. 監視的描述符數量不受限制,它所支持的 fd 上限是最大可以打開文件的數目,這個數字一般遠大于 2048, 舉個例子, 在 1GB 內存的機器上大約是 10 萬左右,具體數目可以 cat /proc/sys/fs/file-max 察看, 一般來說這個數目和系統內存關系很大。select 的最大缺點就是進程打開的 fd 是有數量限制的。這對于連接數量比較大的服務器來說根本不能滿足。雖然也可以選擇多進程的解決方案( Apache 就是這樣實現的),不過雖然 linux 上面創建進程的代價比較小,但仍舊是不可忽視的,加上進程間數據同步遠比不上線程間同步的高效,所以也不是一種完美的方案。
2.IO 的效率不會隨著監視 fd 的數量的增長而下降。epoll 不同于 select 和 poll 輪詢的方式,而是通過每個 fd 定義的回調函數來實現的。只有就緒的 fd 才會執行回調函數。
支持水平觸發和邊沿觸發兩種模式:
3. 水平觸發模式,文件描述符狀態發生變化后,如果沒有采取行動,它將后面反復通知,這種情況下編程相對簡單,libevent 等開源庫很多都是使用的這種模式。
4. 邊沿觸發模式,只告訴進程哪些文件描述符剛剛變為就緒狀態,只說一遍,如果沒有采取行動,那么它將不會再次告知。理論上邊緣觸發的性能要更高一些,但是代碼實現相當復雜(Nginx 使用的邊緣觸發)。
mmap 加速內核與用戶空間的信息傳遞。epoll 是通過內核與用戶空間 mmap 同一塊內存,避免了無謂的內存拷貝。
<br>
<br>
轉載于:https://www.cnblogs.com/sunhongleibibi/p/9190541.html
總結
以上是生活随笔為你收集整理的Socket 编程概述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iscsi-server端配置,以及cl
- 下一篇: mongodb系列~mongodb慢语句