select函數linux
① 關於linux下select函數問題
nfds: 需要檢查的文件描述字個數(即檢查到fd_set的第幾位),數值應該比三組fd_set中所含的最大fd值更大,一般設為三組fd_set中所含的最大fd值加1(如在readset, writeset, exceptset中所含最大的fd為5,則nfds=6,因為fd是從0開始的 )。設這個值是為了提高效率,使函數不必檢查fd_set的所有1024位。 否則函數默認會檢查到最大值
至於你那個補充內容,是這樣的 當調用select()時,由內核根據IO狀態修改fe_set的內容,由此來通知執行了select()的進程哪一socket或文件可讀寫。 這個 是系統內核負責管理的,如果fd1或fd2那個一旦有變化,系統內核會修改其內容就通知select的進程了,如果fd1 fd2都可讀 首先肯定有個先後順序,會記錄下來,挨個處理。
② 誰能告訴我 linux下select函數到底是干什麼用的 貌似我不用它也可以得到我想要的結果啊
select是用來設置超時時間的,其第一個參數本來是一個文件號,假如讀取該文件長時間沒有返回則超時跳出,而這部分代碼將文件號設置為0,說明只是為了控制延時不過看你這部分代碼,明顯只是實現一個比較精確定時的sleep這段代碼之所以這么做,是因為linux本身的sleep函數非常不準(windows也是一樣),在線程較多,cpu任務較重的時候,sleep函數的精確度根本無法達到要求於是你這段代碼使用select來代替sleep更為精準,其精準程度和內核相關,如果內核的滴答頻率決定的,一般是100HZ也有1000hz的(因內核版本不同而不同),也就是說select做多可以精確到10ms,或者1ms,而sleep就做不到於是這段函數最重要的作用就是用高精確的select函數來代替低精確度的sleep函數,實現時間較為精準的延時。可查閱《Linux就該這么學》了解更多Linux介紹。
③ 關於select函數在linux下的問題
因為LINUX下的標准輸出stdout,是行緩沖的,緩沖區大小8192位元組是一個典型值.
必須遇到字元'\n'才真正刷新緩沖區輸出到屏幕上,或者輸出緩沖區被填滿也會輸出到屏幕。
我估計,你等足夠長的時間,等你的修改後的程序把輸出緩沖區填滿,會一次性的列印出一大堆abc.
④ Linux下select函數文件描述符狀態的問題
當然是在有輸入或者輸出時文件描述符的讀寫狀態改變咯,比如標准輸入的文件描述符是0,如果用select來等待0號文件描述符,那麼當在鍵盤上敲字元時開始,就是文件描述符的讀寫狀態改變之時,這時select函數就會返回;對於套接字描述符來說也是這樣,用select來等待一個伺服器描述符,那麼當有新的連接請求時(伺服器描述符等待請求時是一個讀描述符,當有新請求時實際上是有一個輸入),伺服器描述符的讀寫狀態改變,select函數返回。順便說一下,檢查哪個文件描述符發生改變,可以用FD_ISSET宏來進行檢測。
⑤ linux 下 select 函數 延時的問題
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int rc = 0;
struct timeval tv;
while (true)
{
tv.tv_sec = 5;
tv.tv_usec = 0;
rc = select(0, NULL, NULL, NULL, &tv);
printf("select = %d\n", rc);
}
return 0;
}
⑥ 關於linux中select()函數的問題
是的。程序會block在這里,也就是你說的等待。這里等待的意思是操作系統會切換到其他進程去執行。read() write()函數也同樣。不過read() write()根據參數fd的性質,可以是non_block的。這時候,如果不能寫或者沒有數據可讀,會立即出錯返回,然後程序可以去檢查errno知道發生了什麼。
⑦ select 循環定時器 linux
select函數
不是定時器,是I/O的復用,變成
非同步傳輸
。linux的定時器要用信號如alarm來完成秒級定時,用內核定時完成毫秒級定時器。
⑧ 關於Linux下一個小程序中select()函數的問題,這個程序中select到底執行了幾次
原因很簡單。
因為,你按下一個鍵之後,緩沖區裡面有數據了,也就是說,stdin已經發生了一個事件,就是有數據來了。
你一直沒有對緩沖區做任何操作,因此stdin一直保持著有數據的狀態。
如果你在個select返回之後,用fflush清空緩沖區,或者,把緩沖區數據用scanf,getchar等輸入函數給拿出來,數據取完了,stdin緩沖區就沒東西了,再select,狀態就是等待事件發生狀態了。
為了保險,你每次重新把tv給賦值一次.
tv.tv_sec=2;
tv.tv_usec=0;
⑨ 關於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類型的數組當中。
⑩ linux select函數中所指滿足可讀文件描述的條件是什麼
select在串口編程這里是實現監聽串口的數據功能的,如果串口中有接收到數據,select就會返回一個大於0的數,select會把讀文件集合(fd_set)中的其他文件描述符清掉,只留下有數據的串口文件描述符,用FD_ISSET()可以判斷該文件描述符是否在集合中,從而執行相應的代碼。