相對於select來說,poll 也是在指定時間內論詢一定數量的檔案描述符,來測試其中是否有就緒的;比起select來,poll**少,也方便。使用方式的區別也並不大。但是比select要靈活。
poll是乙個系統呼叫,其核心入口函式為sys_poll,sys_poll幾乎不做任何處理直接呼叫do_sys_poll,do_sys_poll的執行過程可以分為三個部分:
1,將使用者傳入的pollfd陣列拷貝到核心空間,因為拷貝操作和陣列長度相關,時間上這是乙個o(n)操作,這一步的**在do_sys_poll中包括從函式開始到呼叫do_poll前的部分。
2,查詢每個檔案描述符對應裝置的狀態,如果該裝置尚未就緒,則在該裝置的等待佇列中加入一項並繼續查詢下一裝置的狀態。查詢完所有裝置後如果沒有乙個裝置就緒,這時則需要掛起當前程序等待,直到裝置就緒或者超時,掛起操作是通過呼叫schedule_timeout執行的。裝置就緒後程序被通知繼續執行,這時再次遍歷所有裝置,以查詢就緒裝置。這一步因為兩次遍歷所有裝置,時間複雜度也是o(n),這裡面不包括等待時間。相關**在do_poll函式中。
3,將獲得的資料傳送到使用者空間並執行釋放記憶體和剝離等待佇列等善後工作,向使用者空間拷貝資料與剝離等待佇列等操作的的時間複雜度同樣是o(n),具體**包括do_sys_poll函式中呼叫do_poll後到結束的部分。
標頭檔案包含:#include
函式原型:int poll(struct pollfd fds, nfds_t nfds, int timeout);
struct pollfd 定義為:
struct pollfd ;
1.fd 為檔案描述符,events 告訴poll 監聽fd 上哪些事件,它是一系列事件按位或。revents 由核心修改,來通知應用程式fd 上實際上發生了哪些事件。
在《unix環境高階程式設計》中有一張events取值的表,如下:
pollin :可讀除高優級外的資料,不阻塞
pollrdnorm:可讀普通資料,不阻塞
pollrdband:可讀o優先資料,不阻塞
pollpri:可讀高優先資料,不阻塞
pollout :可寫普資料,不阻塞
pollwrnorm:與pollout相同
pollwrband:寫非0優先資料,不阻塞
其次revents還有下面取值
pollerr :已出錯
pollhup:已掛起,當以描述符被掛起後,就不能再寫向該描述符,但是仍可以從該描述符讀取到資料。
pollnval:此描述符並不引用一開啟檔案
2.nfds 為要監視的描述符的數目。
3.timeout 為poll的超時時間,單位毫秒。timeout 為-1時,poll永遠阻塞,直到有事件發生。timeout為0時,poll立即返回。
返回值:
返回值》0,表示已偵聽到events指定的事件或者出錯返回給revents;
返回值=0,表示timeout時間到或者出錯返回給revents;
返回值<0,也就是-1,表示出錯。
#include #include #include #include #include #include #include #include #include #include #include #include #define bufsize 1024
int main(int argc, char *ar**)
if((pollfd = (struct pollfd*)calloc(2, sizeof(struct pollfd))) == null) //為struct pollfd分配空間
exit(1);
for(i; i<2; i++) //初始化化struct pollfd結構
printf("nummonitor=%d\n",nummonitor);
while(nummonitor > 0)}}
for(i=0; itest1 和test2為當前路徑下的檔案,裡面均有內容
伺服器端:poll_server.c
#include #include #include #include #include #include #include #include #include #include #define ipaddress "127.0.0.1"
#define port 8787
#define maxline 1024
#define listenq 5
#define open_max 3
#define inftim -1
//函式宣告
//建立套接字並進行繫結
static int socket_bind(const char* ip,int port);
//io多路復用poll
static void do_poll(int listenfd);
//處理多個連線
static void handle_connection(struct pollfd *connfds,int num);
int main(int argc,char *ar**)
static int socket_bind(const char* ip,int port)
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = af_inet;
inet_pton(af_inet,ip,&servaddr.sin_addr);
servaddr.sin_port = htons(port);
if (bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) == -1)
return listenfd;
}static void do_poll(int listenfd)
//測試監聽描述符是否準備好
if (clientfds[0].revents & pollin)
}fprintf(stdout,"accept a new client: %s:%d\n", inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
//將新的連線描述符新增到陣列中
for (i = 1;i < open_max;i++)
}if (i == open_max)
//將新的描述符新增到讀描述符集合中
clientfds[i].events = pollin;
//記錄客戶連線套接字的個數
maxi = (i > maxi ? i : maxi);
if (--nready <= 0)
continue;
}//處理客戶連線
handle_connection(clientfds,maxi);
}}static void handle_connection(struct pollfd *connfds,int num)
// printf("read msg is: ");
write(stdout_fileno,buf,n);
//向客戶端傳送buf
write(connfds[i].fd,buf,n);}}
}
客戶端:poll_client.c
#include #include #include #include #include #include #include #include #include #define maxline 1024
#define ipaddress "127.0.0.1"
#define serv_port 8787
#define max(a,b) (a > b) ? a : b
static void handle_connection(int sockfd);
int main(int argc,char *ar**)
static void handle_connection(int sockfd)
write(stdout_fileno,recvline,n);
}//測試標準輸入是否準備好
if (pfds[1].revents & pollin)
write(sockfd,sendline,n);}}
}
因為在程式中設定了最大連線數為3,所以當第三個連線請求到來的時候,伺服器端關閉,客戶端收到拒絕連線的回應,然後每個客戶端均可收到訊息,客戶端closed.
I O多路復用 poll
函式結構 int poll struct pollfd fds,nfds t nfds,int timeout 引數 返回值 和select一模一樣 events和revents events 關注事件 讀就緒 寫就緒 異常 輸入的時候起作用 revents 輸出結果,輸出的時候起作用 輸入輸出引數...
IO多路復用 select與poll
1.阻塞與非阻塞 阻塞方式block,程序執行到這一函式時必須等待事件發生,如果沒發生,就一直阻塞函式不能返回 非阻塞 non block 程序或執行緒執行不必等待事件發生一旦執行肯定返回以不停返回返回值來反應函式執 況 select就是這樣監視描述符的變化 2.select模型 兩結構體 stru...
poll實現I O多路復用
poll函式原型 引數說明 fds 是乙個struct pollfd結構型別的陣列,用於存放需要檢測其狀態的socket描述符 每當呼叫這個函式之後,系統不會清空這個陣列,操作起來比較方便 特別是對於socket連線比較多的情況下,在一定程度上可以提高處理的效率 這一點與select 函式不同,呼叫...