日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下的I/O多路复用select,poll,epoll浅析

發布時間:2023/11/30 linux 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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

#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #include<netinet/in.h> #include<arpa/inet.h> #include<ctype.h>#define MAXLINE 80 #define SERV_PORT 8000int main(int atgc,char*argv[]) {int i,maxi,maxfd,listenfd,connfd,sockfd;int nready,client[FD_SETSIZE];ssize_t n;fd_set rset,allset;char buf[MAXLINE];char str[INET_ADDRSTRLEN];socklen_t cliaddr_len;struct sockaddr_in cliaddr,servaddr;listenfd = socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));listen(listenfd,20);maxfd = listenfd;maxi = -1;for(i =0;i<FD_SETSIZE;i++){client[i] = -1;}FD_ZERO(&allset);FD_SET(listenfd,&allset);for(;;){rset = allset;nready = select(maxfd+1,&rset,NULL,NULL,NULL);if(nready < 0){printf("select error \n");exit(1);}if(FD_ISSET(listenfd,&rset)){cliaddr_len = sizeof(cliaddr);connfd = accept(listenfd,(struct sockaddr*)&cliaddr,&cliaddr_len);printf("received from %s at PORT %d \n",inet_ntop(AF_INET,&cliaddr.sin_addr,str,sizeof(str)),ntohs(cliaddr.sin_port));for(i=0;i<FD_SETSIZE;i++)if(client[i]<0){client[i]=connfd;break;}if(i==FD_SETSIZE){printf("too many clients\n");exit(1);}FD_SET(connfd,&allset);if(connfd>maxfd)maxfd = connfd;if(i>maxi)maxi = i;if(--nready==0)continue;}for(i=0;i<=maxi;i++){if((sockfd = client[i])<0)continue;if(FD_ISSET(sockfd,&rset)){if((n=read(sockfd,buf,MAXLINE))==0){close(sockfd);FD_CLR(sockfd,&allset);client[i]=-1;}else{int j;for(j=0;j<n;j++)buf[j]=toupper(buf[j]);write(sockfd,buf,n);}if(--nready ==0)break;}}}close(listenfd);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
  • 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浅析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。