Linux下的I/O多路复用select,poll,epoll浅析
轉載:http://blog.csdn.net/u011573853/article/details/52105365
一,什么是I/O多路復用?
所謂的I/O多路復用在英文中其實叫 I/O multiplexing. 就是單個線程,通過記錄跟蹤每個I/O流(sock)的狀態,來同時管理多個I/O流 。)?
I/O multiplexing 這里面的 multiplexing 指的其實是在單個線程通過記錄跟蹤每一個Sock(I/O流)的狀態(對應空管塔里面的Fight progress strip槽)來同時管理多個I/O流. 發明它的原因,是盡量多的提高服務器的吞吐量?
如圖?
?
二,多路復用的方式很多今天說一下select原理:?
select函數會等待,直到描述符句柄中有可用資源(可讀、可寫、異常)時返回,返回值是可用資源(可讀/可寫/異常等)描述符的個數(>0),0代表超時,-1代表錯誤。具體到內核大致是:當應用程序調用select() 函數, 內核就會相應調用 poll_wait(), 把當前進程添加到相應設備的等待隊列上,然后將該應用程序進程設置為睡眠狀態。直到該設備上的數據可以獲取,然后調用wake_up()喚醒該應用程序進程。select每次輪訓都會遍歷所有描述符句柄。?
使用select模型的路徑圖如下?
?
三,函數?
int select(int nfds, fd_set *readfds, fd_set *writefds,?
fd_set *exceptfds, struct timeval *timeout);?
nfds: 監控的文件描述符集里最大文件描述符加1,因為此參數會告訴內核檢測前多少個文件描述符的狀態?
readfds:監控有讀數據到達文件描述符集合,傳入傳出參數?
writefds:監控寫數據到達文件描述符集合,傳入傳出參數?
exceptfds:監控異常發生達文件描述符集合,如帶外數據到達異常,傳入傳出參數?
timeout:定時阻塞監控時間,3種情況?
1.NULL,永遠等下去?
2.設置timeval,等待固定時間?
3.設置timeval里時間均為0,檢查描述字后立即返回,輪詢?
struct timeval {?
long tv_sec; /* seconds */?
long tv_usec; /* microseconds */?
};?
void FD_CLR(int fd, fd_set *set); 把文件描述符集合里fd清0?
int FD_ISSET(int fd, fd_set *set); 測試文件描述符集合里fd是否置1?
void FD_SET(int fd, fd_set *set); 把文件描述符集合里fd位置1?
void FD_ZERO(fd_set *set); 把文件描述符集合里所有位清0
select函數執行結果:執行成功則返回文件描述詞狀態已改變的個數,如果返回0代表在描述詞狀態改變前已超過timeout時間,沒有返回;當有錯誤發生時則返回-1,錯誤原因存于errno,此時參數readfds,writefds,exceptfds和timeout的值變成不可預測。錯誤?
值可能為:?
EBADF 文件描述詞為無效的或該文件已關閉?
EINTR 此調用被信號所中斷?
EINVAL 參數n 為負值。?
ENOMEM 核心內存不足?
要想理解好select模型就要理解好fd_set,為說明方便,取fd_set長度為1字節,fd_set中的每一bit可以對應一個文件描述符fd。則1字節長的fd_set最大可以對應8個fd。?
(1)執行fd_set set;FD_ZERO(&set);則set用位表示是0000,0000。?
(2)若fd=5,執行FD_SET(fd,&set);后set變為0001,0000(第5位置為1)?
(3)若再加入fd=2,fd=1,則set變為0001,0011?
(4)執行select(6,&set,0,0,0)阻塞等待?
(5)若fd=1,fd=2上都發生可讀事件,則select返回,此時set變為0000,0011。注意:沒有事件發生的fd=5被清空。?
基于上面的討論,可以輕松得出select模型的特點:?
(1)可監控的文件描述符個數取決與sizeof(fd_set)的值。我這邊服務器上sizeof(fd_set)=128,每bit表示一個文件描述符,則我服務器上支持的最大文件描述符是128*8=1024。?
(2)將fd加入select監控集的同時,還要再使用一個數據結構array保存放到select監控集中的fd,一是用于再select返回后,array作為源數據和fd_set進行FD_ISSET判斷。二是select返回后會把以前加入的但并無事件發生的fd清空,則每次開始 select前都要重新從array取得fd逐一加入(FD_ZERO最先),掃描array的同時取得fd最大值maxfd,用于select的第一個參數。?
(3)可見select模型必須在select前循環array(加fd,取maxfd),select返回后循環array(FD_ISSET判斷是否有時間發生)。
四,優缺點?
1,簡單,可以在多種系統上使用?
2,select能監聽的文件描述符個數受限于FD_SETSIZE,一般為1024,單純改變進程打開?
的文件描述符個數并不能改變select監聽文件個數?
3,解決1024以下客戶端時使用select是很合適的,但如果鏈接客戶端過多,select采用的是輪詢模型,會大大降低服務器響應效率,不應在select上投入更多精力?
五 案例?
server
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
client
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #define MAXLINE 80 #define SERV_PORT 8000int main(int argc,char *argv[]) {struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd,n;sockfd = socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET,"192.168.1.103",&servaddr.sin_addr);servaddr.sin_port = htons(SERV_PORT);connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));while(fgets(buf,MAXLINE,stdin)!=NULL){write(sockfd,buf,strlen(buf));n = read(sockfd,buf,MAXLINE);if (n==0){printf("the other ha closed\n");break;}elsewrite(STDOUT_FILENO,buf,n);}close(sockfd);return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
總結
以上是生活随笔為你收集整理的Linux下的I/O多路复用select,poll,epoll浅析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DNF在哪里遴选属性
- 下一篇: 神犬小七3剧情介绍