日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Linux网络编程——I/O复用之poll函数

發(fā)布時間:2025/4/9 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux网络编程——I/O复用之poll函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、回顧前面的select

select優(yōu)點:

目前幾乎在所有的平臺上支持,其良好跨平臺支持也是它的一個優(yōu)點

select缺點:

1.每次調(diào)用 select(),都需要把 fd 集合從用戶態(tài)拷貝到內(nèi)核態(tài),這個開銷在 fd 很多時會很大,同時每次調(diào)用 select() 都需要在內(nèi)核遍歷傳遞進來的所有 fd,這個開銷在 fd 很多時也很大。

?

2.單個進程能夠監(jiān)視的文件描述符的數(shù)量存在最大限制,在 Linux 上一般為 1024,可以通過修改宏定義甚至重新編譯內(nèi)核的方式提升這一限制,但是這樣也會造成效率的降低

二、poll函數(shù)概述

select() 和 poll() 系統(tǒng)調(diào)用的本質(zhì)一樣,poll() 的機制與 select() 類似,與 select() 在本質(zhì)上沒有多大差別,管理多個描述符也是進行輪詢,根據(jù)描述符的狀態(tài)進行處理,但是 poll()沒有最大文件描述符數(shù)量的限制(但是數(shù)量過大后性能也是會下降)。poll() 和 select() 同樣存在一個缺點就是,包含大量文件描述符的數(shù)組被整體復制于用戶態(tài)和內(nèi)核的地址空間之間,而不論這些文件描述符是否就緒,它的開銷隨著文件描述符數(shù)量的增加而線性增大。

poll()函數(shù)介紹

頭文件: [csharp]?view plain?copy
  • #include?<poll.h>??
  • 函數(shù)體: [csharp]?view plain?copy
  • int?poll(struct?pollfd?*fds,?nfds_t?nfds,?int?timeout);??
  • 功能: 監(jiān)視并等待多個文件描述符的屬性變化

    參數(shù):

    fds:指向一個結(jié)構(gòu)體數(shù)組的第0個元素的指針,每個數(shù)組元素都是一個struct pollfd結(jié)構(gòu),用于指定測試某個給定的fd的條件

    ?

    [csharp]?view plain?copy
  • struct?pollfd{??
  • ????int?fd;?????????//文件描述符??
  • ????short?events;???//等待的事件??
  • ????short?revents;??//實際發(fā)生的事件??
  • };??
  • fd:每一個 pollfd 結(jié)構(gòu)體指定了一個被監(jiān)視的文件描述符,可以傳遞多個結(jié)構(gòu)體,指示 poll() 監(jiān)視多個文件描述符。

    events:指定監(jiān)測fd的事件(輸入、輸出、錯誤),每一個事件有多個取值,如下:



    revents:revents 域是文件描述符的操作結(jié)果事件,內(nèi)核在調(diào)用返回時設(shè)置這個域。events 域中請求的任何事件都可能在 revents 域中返回.

    ?

    注意:每個結(jié)構(gòu)體的 events 域是由用戶來設(shè)置,告訴內(nèi)核我們關(guān)注的是什么,而 revents 域是返回時內(nèi)核設(shè)置的,以說明對該描述符發(fā)生了什么事件

    ?

    nfds:用來指定第一個參數(shù)數(shù)組元素個數(shù)

    timeout: 指定等待的毫秒數(shù),無論 I/O 是否準備好,poll() 都會返回.

    ?

    ?

    返回值:

    成功時,poll() 返回結(jié)構(gòu)體中 revents 域不為 0 的文件描述符個數(shù);如果在超時前沒有任何事件發(fā)生,poll()返回 0;


    失敗時,poll() 返回 -1,并設(shè)置 errno 為下列值之一:

    EBADF:一個或多個結(jié)構(gòu)體中指定的文件描述符無效。

    EFAULT:fds 指針指向的地址超出進程的地址空間。

    EINTR:請求的事件之前產(chǎn)生一個信號,調(diào)用可以重新發(fā)起。

    EINVAL:nfds 參數(shù)超出 PLIMIT_NOFILE 值。

    ENOMEM:可用內(nèi)存不足,無法完成請求。

    ?

    三、poll示例舉例

    用poll實現(xiàn)udp同時收發(fā)

    代碼: [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];//監(jiān)測文件描述結(jié)構(gòu)體數(shù)組: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);??
  • ??????
  • ????//創(chuàng)建套接字??
  • ????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;??//udp描述符??
  • ??????
  • ????fds[0].events?=?POLLIN;?//?普通或優(yōu)先級帶數(shù)據(jù)可讀????
  • ????fds[1].events?=?POLLIN;?//?普通或優(yōu)先級帶數(shù)據(jù)可讀??
  • ??????
  • ????while(1)??
  • ????{?????
  • ????????//?監(jiān)視并等待多個文件(標準輸入,udp套接字)描述符的屬性變化(是否可讀)????
  • ????????//?沒有屬性變化,這個函數(shù)會阻塞,直到有變化才往下執(zhí)行,這里沒有設(shè)置超時????
  • ????????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);//給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?){?//udp套接字????
  • ????????????????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;??
  • }??


  • 運行結(jié)果:

    轉(zhuǎn)載于:https://www.cnblogs.com/jiangzhaowei/p/8831083.html

    總結(jié)

    以上是生活随笔為你收集整理的Linux网络编程——I/O复用之poll函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。