當前位置:首頁 » 操作系統 » selectlinux

selectlinux

發布時間: 2022-11-14 18:26:40

1. 關於linux下的select/epoll

select這個系統調用的原型如下

第一個參數nfds用來告訴內核 要掃描的socket fd的數量+1 ,select系統調用最大接收的數量是1024,但是如果每次都去掃描1024,實際上的數量並不多,則效率太低,這里可以指定需要掃描的數量。 最大數量為1024,如果需要修改這個數量,則需要重新編譯Linux內核源碼
第2、3、4個參數分別是readfds、writefds、exceptfds,傳遞的參數應該是fd_set 類型的引用,內核會檢測每個socket的fd, 如果沒有讀事件,就將對應的fd從第二個參數傳入的fd_set中移除,如果沒有寫事件,就將對應的fd從第二個參數的fd_set中移除,如果沒有異常事件,就將對應的fd從第三個參數的fd_set中移除 。這里我們應該 要將實際的readfds、writefds、exceptfds拷貝一份副本傳進去,而不是傳入原引用,因為如果傳遞的是原引用,某些socket可能就已經丟失
最後一個參數是等待時間, 傳入0表示非阻塞,傳入>0表示等待一定時間,傳入NULL表示阻塞,直到等到某個socket就緒

FD_ZERO()這個函數將fd_set中的所有bit清0,一般用來進行初始化等。
FD_CLR()這個函數用來將bitmap(fd_set )中的某個bit清0,在客戶端異常退出時就會用到這個函數,將fd從fd_set中刪除。
FD_ISSET()用來判斷某個bit是否被置1了,也就是判斷某個fd是否在fd_set中。
FD_SET()這個函數用來將某個fd加入fd_set中,當客戶端新加入連接時就會使用到這個函數。

epoll_create系統調用用來創建epfd,會在開辟一塊內存空間(epoll的結構空間)。size為epoll上能關注的最大描述符數,不夠會進行擴展,size只要>0就行,早期的設計size是固定大小,但是現在size參數沒什麼用,會自動擴展。
返回值是epfd,如果為-1則說明創建epoll對象失敗

第一個參數epfd傳入的就是epoll_create返回的epfd。
第二個參數傳入對應操作的宏,包括 增刪改(EPOLL_CTL_ADD、EPOLL_CTL_DEL、EPOLL_CTL_MOD)
第三個參數傳入的是 需要增刪改的socket的fd
第四個參數傳入的是 需要操作的fd的哪些事件 ,具體的事件可以看後續。
返回值是一個int類型,如果為-1則說明操作失敗

第一個參數是epfd,也就是epoll_create的返回值。
第二個參數是一個epoll_event類型的指針,也就是傳入的是一個數組指針。 內核會將就緒的socket的事件拷貝到這個數組中,用戶可以根據這個數組拿到事件和消息等
第三個參數是maxevents,傳入的是 第二個參數的數組的容量
第四個參數是timeout, 如果設為-1一直阻塞直到有就緒數據為止,如果設為0立即返回,如果>0那麼阻塞一段時間
返回值是一個int類型,也就是就緒的socket的事件的數量(內核拷貝給用戶的events的元素的數量),通過這個數量可以進行遍歷處理每個事件

一般需要傳入 ev.data.fd 和 ev.events ,也就是fd和需要監控的fd的事件。事件如果需要傳入多個,可以通過按位與來連接,比如需要監控讀寫事件,只需要像如下這樣操作即可: ev.events=EPOLLIN | EPOLLOUT 。

LT(水平觸發), 默認 的工作模式, 事件就緒後用戶可以選擇處理和不處理,如果用戶不處理,內核會對這部分數據進行維護,那麼下次調用epoll_wait()時仍舊會打包出來
ET(邊緣觸發),事件就緒之後, 用戶必須進行處理 ,因為內核把事件打包出來之後就把對應的就緒事件給清掉了, 如果不處理那麼就緒事件就沒了 。ET可以減少epoll事件被重復觸發的次數,效率比LT高。
如果需要設置為邊緣觸發只需要設置事件為類似 ev.events=EPOLLIN | EPOLLET 即可

select/poll/epoll是nio多路復用技術, 傳統的bio無法實現C10K/C100K ,也就是無法滿足1w/10w的並發量,在這么高的並發量下,在進行上下文切換就很容易將伺服器的負載拉飛。

1.將fd_set從用戶態拷貝到內核態
2.根據fd_set掃描內存中的socket的fd的狀態,時間復雜度為O(n)
3.檢查fd_set,如果有已經就緒的socket,就給對應的socket的fd打標記,那麼就return 就緒socket的數量並喚醒當前線程,如果沒有就緒的socket就繼續阻塞當前線程直到有socket就緒才將當前線程喚醒。
4.如果想要獲取當前已經就緒的socket列表,則還需要進行一次系統調用,使用O(n)的時間去掃描socket的fd列表,將已經打上標記的socket的fd返回。

CPU在同一個時刻只能執行一個程序,通過RR時間片輪轉去切換執行各個程序。沒有被掛起的進程(線程)則在工作隊列中排隊等待CPU的執行,將進程(線程)從工作隊列中移除就是掛起,反映到Java層面的就是線程的阻塞。

什麼是中斷?當我們使用鍵盤、滑鼠等IO設備的時候,會給主板一個電流信號,這個電流信號就給CPU一個中斷信號,CPU執行完當前的指令便會保存現場,然後執行鍵盤/滑鼠等設備的中斷程序,讓中斷程序獲取CPU的使用權,在中斷程序後又將現場恢復,繼續執行之前的進程。

如果第一次沒檢測到就緒的socket,就要將其進程(線程)從工作隊列中移除,並加入到socket的等待隊列中。

socket包含讀緩沖區+寫緩沖區+等待隊列(放線程或eventpoll對象)

當從客戶端往伺服器端發送數據時,使用TCP/IP協議將通過物理鏈路、網線發給伺服器的網卡設備,網卡的DMA設備將接收到的的數據寫入到內存中的一塊區域(網卡緩沖區),然後會給CPU發出一個中斷信號,CPU執行完當前指令則會保存現場,然後網卡的中斷程序就獲得了CPU的使用權,然後CPU便開始執行網卡的中斷程序,將內存中的緩存區中的數據包拿出,判斷埠號便可以判斷它是哪個socket的數據,將數據包寫入對應的socket的讀(輸入)緩沖區,去檢查對應的socket的等待隊列有沒有等待著的進程(線程),如果有就將該線程(進程)從socket的等待隊列中移除,將其加入工作隊列,這時候該進程(線程)就再次擁有了CPU的使用許可權,到這里中斷程序就結束了。

之後這個進程(線程)就執行select函數再次去檢查fd_set就能發現有socket緩沖區中有數據了,就將該socket的fd打標記,這個時候select函數就執行完了,這時候就會給上層返回一個int類型的數值,表示已經就緒的socket的數量或者是發生了錯誤。這個時候就再進行內核態到用戶態的切換,對已經打標記的socket的fd進行處理。

將原本1024bit長度的bitmap(fd_set)換成了數組的方式傳入 ,可以 解決原本1024個不夠用的情況 ,因為傳入的是數組,長度可以不止是1024了,因此socket數量可以更多,在Kernel底層會將數組轉換成鏈表。

在十多年前,linux2.6之前,不支持epoll,當時可能會選擇用Windows/Unix用作伺服器,而不會去選擇Linux,因為select/poll會隨著並發量的上升,性能變得越來越低,每次都得檢查所有的Socket列表。

1.select/poll每次調用都必須根據提供所有的socket集合,然後就 會涉及到將這個集合從用戶空間拷貝到內核空間,在這個過程中很耗費性能 。但是 其實每次的socket集合的變化也許並不大,也許就1-2個socket ,但是它會全部進行拷貝,全部進行遍歷一一判斷是否就緒。

2.select/poll的返回類型是int,只能代表當前的就緒的socket的數量/發生了錯誤, 如果還需要知道是哪些socket就緒了,則還需要再次使用系統調用去檢查哪些socket是就緒的,又是一次O(n)的操作,很耗費性能

1.epoll在Kernel內核中存儲了對應的數據結構(eventpoll)。我們可以 使用epoll_create()這個系統調用去創建一個eventpoll對象 ,並返回eventpoll的對象id(epfd),eventpoll對象主要包括三個部分:需要處理的正在監聽的socket_fd列表(紅黑樹結構)、socket就緒列表以及等待隊列(線程)。

2.我們可以使用epoll_ctl()這個系統調用對socket_fd列表進行CRUD操作,因為可能頻繁地進行CRUD,因此 socket_fd使用的是紅黑樹的結構 ,讓其效率能更高。epoll_ctl()傳遞的參數主要是epfd(eventpoll對象id)。

3.epoll_wait()這個系統調用默認會 將當前進程(線程)阻塞,加入到eventpoll對象的等待隊列中,直到socket就緒列表中有socket,才會將該進程(線程)重新加入工作隊列 ,並返回就緒隊列中的socket的數量。

socket包含讀緩沖區、寫緩沖區和等待隊列。當使用epoll_ctl()系統調用將socket新加入socket_fd列表時,就會將eventpoll對象引用加到socket的等待隊列中, 當網卡的中斷程序發現socket的等待隊列中不是一個進程(線程),而是一個eventpoll對象的引用,就將socket引用追加到eventpoll對象的就緒列表的尾部 。而eventpoll對象中的等待隊列存放的就是調用了epoll_wait()的進程(線程),網卡的中斷程序執行會將等待隊列中的進程(線程)重新加入工作隊列,讓其擁有佔用CPU執行的資格。epoll_wait()的返回值是int類型,返回的是就緒的socket的數量/發生錯誤,-1表示發生錯誤。

epoll的參數有傳入一個epoll_event的數組指針(作為輸出參數),在調用epoll_wait()返回的同時,Kernel內核還會將就緒的socket列表添加到epoll_event類型的數組當中。

2. linux下select用阻塞的情況怎麼返回

既然select已經阻塞了,它就不會返回,除非有信號.你要非得讓它返回的話就用信號吧.
不過一般用select時都不會設為阻塞,因為你設為阻塞不是跟沒用select一樣嗎?recv本身也是阻塞的,
而且主動close套接字時還會返回0,可以判斷

3. linux下的select函數是幹嘛的

不是用得很好嗎?精確延時功能。
此外,可以用來判斷讀寫操作是否在指定時間內就緒。

4. linux下select用阻塞的情況怎麼返回

既然select已經阻塞了,它就不會返回,除非有信號.你要非得讓它返回的話就用信號吧.
不過一般用select時都不會設為阻塞,因為你設為阻塞不是跟沒用select一樣嗎?recv本身也是阻塞的,而且主動close套接字時還會返回0,可以判斷.

5. linux select 怎麼理解

linux select函數詳解
在Linux中,我們可以使用select函數實現I/O埠的復用,傳遞給 select函數的參數會告訴內核:
•我們所關心的文件描述符
•對每個描述符,我們所關心的狀態。(我們是要想從一個文件描述符中讀或者寫,還是關注一個描述符中是否出現異常)
•我們要等待多長時間。(我們可以等待無限長的時間,等待固定的一段時間,或者根本就不等待)
從 select函數返回後,內核告訴我們一下信息:
•對我們的要求已經做好准備的描述符的個數
•對於三種條件哪些描述符已經做好准備.(讀,寫,異常)
有了這些返回信息,我們可以調用合適的I/O函數(通常是 read 或 write),並且這些函數不會再阻塞.
#include <sys/select.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);
返回:做好准備的文件描述符的個數,超時為0,錯誤為 -1.
首先我們先看一下最後一個參數。它指明我們要等待的時間:
struct timeval{
long tv_sec; /*秒 */
long tv_usec; /*微秒 */
}
有三種情況:
timeout == NULL 等待無限長的時間。等待可以被一個信號中斷。當有一個描述符做好准備或者是捕獲到一個信號時函數會返回。如果捕獲到一個信號, select函數將返回 -1,並將變數 erro設為 EINTR。
timeout->tv_sec == 0 &&timeout->tv_usec == 0不等待,直接返回。加入描述符集的描述符都會被測試,並且返回滿足要求的描述符的個數。這種方法通過輪詢,無阻塞地獲得了多個文件描述符狀態。
timeout->tv_sec !=0 ||timeout->tv_usec!= 0 等待指定的時間。當有描述符符合條件或者超過超時時間的話,函數返回。在超時時間即將用完但又沒有描述符合條件的話,返回 0。對於第一種情況,等待也會被信號所中斷。

6. Linux下select函數文件描述符狀態的問題

當然是在有輸入或者輸出時文件描述符的讀寫狀態改變咯,比如標准輸入的文件描述符是0,如果用select來等待0號文件描述符,那麼當在鍵盤上敲字元時開始,就是文件描述符的讀寫狀態改變之時,這時select函數就會返回;對於套接字描述符來說也是這樣,用select來等待一個伺服器描述符,那麼當有新的連接請求時(伺服器描述符等待請求時是一個讀描述符,當有新請求時實際上是有一個輸入),伺服器描述符的讀寫狀態改變,select函數返回。順便說一下,檢查哪個文件描述符發生改變,可以用FD_ISSET宏來進行檢測。

7. linux select函數中所指滿足可讀文件描述的條件是什麼

select在串口編程這里是實現監聽串口的數據功能的,如果串口中有接收到數據,select就會返回一個大於0的數,select會把讀文件集合(fd_set)中的其他文件描述符清掉,只留下有數據的串口文件描述符,用FD_ISSET()可以判斷該文件描述符是否在集合中,從而執行相應的代碼。

8. linux select檢測為啥是監聽套接字

select系統調用的作用就是讓程序在多個文件描述符上進行等待,而套接字也是屬於文件描述符的一種,所以伺服器程序就可以利用select系統調用,在多個套接字上等待客戶端請求,從而達到同時處理多個客戶端的效果,而等待客戶端請求就需要用listen調用對客戶端進行監聽,select調用檢測的當然就是監聽套接字咯。
select系統調用是檢測一個已打開的文件描述符的集合(這個集合是一個fd_set類型的數據結構),伺服器程序需要創建這個集合,創建時需要用listen調用讓套接字處於監聽狀態,只有這樣當有一個新的連接發生時,描述符才會有活動發生,才能夠被檢測到。

9. linux下的select函數是幹嘛的

select是用來設置超時時間的,其第一個參數本來是一個文件號,假如讀取該文件長時間沒有返回則超時跳出,而這部分代碼將文件號設置為0,說明只是為了控制延時
不過看你這部分代碼,明顯只是實現一個比較精確定時的sleep
這段代碼之所以這么做,是因為linux本身的sleep函數非常不準(windows也是一樣),在線程較多,cpu任務較重的時候,sleep函數的精確度根本無法達到要求
於是你這段代碼使用select來代替sleep更為精準,其精準程度和內核相關,如果內核的滴答頻率決定的,一般是100HZ也有1000hz的(因內核版本不同而不同),也就是說select做多可以精確到10ms,或者1ms,而sleep就做不到
於是
這段函數最重要的作用就是用高精確的select函數來代替低精確度的sleep函數,實現時間較為精準的延時

10. 誰能告訴我 linux下select函數到底是干什麼用的 貌似我不用它也可以得到我想要的結果啊

select是用來設置超時時間的,其第一個參數本來是一個文件號,假如讀取該文件長時間沒有返回則超時跳出,而這部分代碼將文件號設置為0,說明只是為了控制延時不過看你這部分代碼,明顯只是實現一個比較精確定時的sleep這段代碼之所以這么做,是因為linux本身的sleep函數非常不準(windows也是一樣),在線程較多,cpu任務較重的時候,sleep函數的精確度根本無法達到要求於是你這段代碼使用select來代替sleep更為精準,其精準程度和內核相關,如果內核的滴答頻率決定的,一般是100HZ也有1000hz的(因內核版本不同而不同),也就是說select做多可以精確到10ms,或者1ms,而sleep就做不到於是這段函數最重要的作用就是用高精確的select函數來代替低精確度的sleep函數,實現時間較為精準的延時。可查閱《Linux就該這么學》了解更多Linux介紹。

熱點內容
換編程題庫 發布:2024-05-18 18:00:58 瀏覽:561
如何使用伺服器ip直連網站 發布:2024-05-18 18:00:49 瀏覽:431
三星n7100哪個安卓版本好用 發布:2024-05-18 17:55:41 瀏覽:489
萬國覺醒採集腳本源碼 發布:2024-05-18 17:55:39 瀏覽:946
sqlserver加欄位 發布:2024-05-18 17:54:53 瀏覽:927
安卓手機如何清除應用記錄 發布:2024-05-18 17:31:37 瀏覽:639
查看存儲過程許可權 發布:2024-05-18 17:18:33 瀏覽:191
php類self 發布:2024-05-18 17:15:03 瀏覽:894
手機2b2t的伺服器地址是多少 發布:2024-05-18 17:14:56 瀏覽:188
戴爾8490哪個配置比較合理 發布:2024-05-18 17:14:51 瀏覽:168