生活随笔
收集整理的這篇文章主要介紹了
Linux网络编程——I/O复用之poll函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、回顧前面的select
select優點:
目前幾乎在所有的平臺上支持,其良好跨平臺支持也是它的一個優點
select缺點:
1.每次調用 select(),都需要把 fd 集合從用戶態拷貝到內核態,這個開銷在 fd 很多時會很大,同時每次調用 select() 都需要在內核遍歷傳遞進來的所有 fd,這個開銷在 fd 很多時也很大。
?
2.單個進程能夠監視的文件描述符的數量存在最大限制,在 Linux 上一般為 1024,可以通過修改宏定義甚至重新編譯內核的方式提升這一限制,但是這樣也會造成效率的降低
二、poll函數概述
select() 和 poll() 系統調用的本質一樣,poll() 的機制與 select() 類似,與 select() 在本質上沒有多大差別,管理多個描述符也是進行輪詢,根據描述符的狀態進行處理,但是 poll()沒有最大文件描述符數量的限制(但是數量過大后性能也是會下降)。poll() 和 select() 同樣存在一個缺點就是,包含大量文件描述符的數組被整體復制于用戶態和內核的地址空間之間,而不論這些文件描述符是否就緒,它的開銷隨著文件描述符數量的增加而線性增大。
poll()函數介紹
頭文件:
[csharp]?view plain
?copy #include?<poll.h>?? 函數體:
[csharp]?view plain
?copy int?poll(struct?pollfd?*fds,?nfds_t?nfds,?int?timeout);?? 功能: 監視并等待多個文件描述符的屬性變化
參數:
fds:指向一個結構體數組的第0個元素的指針,每個數組元素都是一個struct pollfd結構,用于指定測試某個給定的fd的條件
?
[csharp]?view plain
?copy struct?pollfd{??????int?fd;?????????????short?events;???????short?revents;??};?? fd:每一個 pollfd 結構體指定了一個被監視的文件描述符,可以傳遞多個結構體,指示 poll() 監視多個文件描述符。
events:指定監測fd的事件(輸入、輸出、錯誤),每一個事件有多個取值,如下:
revents:revents 域是文件描述符的操作結果事件,內核在調用返回時設置這個域。events 域中請求的任何事件都可能在 revents 域中返回.
?
注意:每個結構體的 events 域是由用戶來設置,告訴內核我們關注的是什么,而 revents 域是返回時內核設置的,以說明對該描述符發生了什么事件
?
nfds:用來指定第一個參數數組元素個數
timeout: 指定等待的毫秒數,無論 I/O 是否準備好,poll() 都會返回.
?
?
返回值:
成功時,poll() 返回結構體中 revents 域不為 0 的文件描述符個數;如果在超時前沒有任何事件發生,poll()返回 0;
失敗時,poll() 返回 -1,并設置 errno 為下列值之一:
EBADF:一個或多個結構體中指定的文件描述符無效。
EFAULT:fds 指針指向的地址超出進程的地址空間。
EINTR:請求的事件之前產生一個信號,調用可以重新發起。
EINVAL:nfds 參數超出 PLIMIT_NOFILE 值。
ENOMEM:可用內存不足,無法完成請求。
?
三、poll示例舉例
用poll實現udp同時收發
代碼:
[csharp]?view plain
?copy #include?<string.h>??#include?<stdio.h>??#include?<stdlib.h>??#include?<unistd.h>??#include?<sys/select.h>??#include?<sys/time.h>??#include?<sys/socket.h>??#include?<netinet/in.h>??#include?<arpa/inet.h>??#include?<poll.h>????int?main(int?argc,char?*argv[])??{??????int?udpfd?=?0;??????int?ret?=?0;??????struct?pollfd?fds[2];????struct?sockaddr_in?saddr;??????struct?sockaddr_in?caddr;????????bzero(&saddr,sizeof(saddr));??????saddr.sin_family?=?AF_INET;??????saddr.sin_port???=?htons(8000);??????saddr.sin_addr.s_addr?=?htonl(INADDR_ANY);????????????bzero(&caddr,sizeof(caddr));??????caddr.sin_family??=?AF_INET;??????caddr.sin_port????=?htons(8000);????????????????if(?(udpfd?=?socket(AF_INET,SOCK_DGRAM,?0))?<?0)??????{??????????perror("socket?error");??????????exit(-1);??????}????????????????if(bind(udpfd,?(struct?sockaddr*)&saddr,?sizeof(saddr))?!=?0)??????{??????????perror("bind?error");??????????close(udpfd);?????????????????exit(-1);??????}????????printf("input:?\"sayto?192.168.220.X\"?to?sendmsg?to?somebody\033[32m\n");????????fds[0].fd?=?0;??????????fds[1].fd?=?udpfd;????????????fds[0].events?=?POLLIN;?????fds[1].events?=?POLLIN;???????????while(1)??????{?????????????????????????????ret?=?poll(fds,?2,?-1);?????????????????????write(1,"UdpQQ:",6);????????????????????if(ret?==?-1){?????????????perror("poll()");????????????}??????????else?if(ret?>?0){?????????????char?buf[100]?=?{0};????????????????if(?(?fds[0].revents?&?POLLIN?)?==??POLLIN?){???????????????????????????????????fgets(buf,?sizeof(buf),?stdin);??????????????????buf[strlen(buf)?-?1]?=?'\0';??????????????????if(strncmp(buf,?"sayto",?5)?==?0)??????????????????{??????????????????????char?ipbuf[16]?=?"";??????????????????????inet_pton(AF_INET,?buf+6,?&caddr.sin_addr);????????????????????printf("\rsay?to?%s\n",inet_ntop(AF_INET,&caddr.sin_addr,ipbuf,sizeof(ipbuf)));??????????????????????continue;??????????????????}??????????????????else?if(strcmp(buf,?"exit")==0)??????????????????{??????????????????????close(udpfd);??????????????????????exit(0);??????????????????}??????????????????sendto(udpfd,?buf,?strlen(buf),0,(struct?sockaddr*)&caddr,?sizeof(caddr));????????????????????????????????????}??????????????else?if(?(?fds[1].revents?&?POLLIN?)?==??POLLIN?){?????????????????struct?sockaddr_in?addr;??????????????????char?ipbuf[INET_ADDRSTRLEN]?=?"";??????????????????socklen_t?addrlen?=?sizeof(addr);????????????????????????????????????bzero(&addr,sizeof(addr));????????????????????????????????????recvfrom(udpfd,?buf,?100,?0,?(struct?sockaddr*)&addr,?&addrlen);??????????????????printf("\r\033[31m[%s]:\033[32m%s\n",inet_ntop(AF_INET,&addr.sin_addr,ipbuf,sizeof(ipbuf)),buf);????????????????}????????????????????????????}??????????else?if(0?==?ret){?????????????printf("time?out\n");????????????}????????}????????????return?0;??}?? 運行結果:
轉載于:https://www.cnblogs.com/jiangzhaowei/p/8831083.html
總結
以上是生活随笔為你收集整理的Linux网络编程——I/O复用之poll函数的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。