poll函數


poll函數

  poll函數起源於SVR3,最初局限於流設備。SVR4取消了這種限制,允許poll工作在任何描述字上。poll提供的功能與select類似,不過在處理流設備時,它能夠提供額外的信息。

  1.#include <poll.h>

  2.

  3.int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);

  4.               返回:就緒描述字的個數,0-超時,-1-出錯

  第一個參數是指向一個結構數組第一個元素的指針。每個數組元素都是一個pollfd結構,用於指定測試某個給定描述字fd的條件。

  struct pollfd{

  int fd;              //descriptor to check

  short events;    //events of interest on fd

  short revents;   //events that occurred on fd

  };

  要測試的條件由events成員指定,而返回的結果則在revents中存儲。常用條件及含意說明如下:

poll函數可用的測試值

常量 說明
POLLIN 普通或優先級帶數據可讀
POLLRDNORM 普通數據可讀
POLLRDBAND 優先級帶數據可讀
POLLPRI 高優先級數據可讀
POLLOUT 普通數據可寫
POLLWRNORM 普通數據可寫
POLLWRBAND 優先級帶數據可寫
POLLERR 發生錯誤
POLLHUP 發生掛起
POLLNVAL 描述字不是一個打開的文件

 

  注意:后三個只能作為描述字的返回結果存儲在revents中,而不能作為測試條件用於events中。

  第二個參數nfds是用來指定數組fdarray的長度。

  最后一個參數timeout是指定poll函數返回前等待多長時間。它的取值如下:

 

timeout值 說明
INFTIM 永遠等待
0 立即返回,不阻塞進程
>0 等待指定數目的毫秒數

 

  一個使用poll的網絡程序例子:

  001./**

  002.  *TCP回射服務器的服務端程序

  003.  */

  004.#include <stdio.h>

  005.#include <stdlib.h>

  006.#include <unistd.h>

  007.#include <sys/socket.h>

  008.#include <sys/types.h>

  009.#include <netinet/in.h>

  010.#include <netdb.h>

  011.#include <string.h>

  012.#include <errno.h>

  013.#include <poll.h>   //for poll

  014.

  015.#define LISTENQ 1024

  016.#define MAXLINE 1024

  017.#define OPEN_MAX 50000

  018.#define SERVER_PORT 3333

  019.

  020.#ifndef INFTIM     /*按照書上解釋:POSIX規范要求INFTIM在頭文件<poll.h>中定義,不過*/

  021.#define INFTIM -1  /*許多系統仍然把它定義在頭文件<sys/stropts.h>中,但是經過我的測試*/

  022.#endif             /*即使都包含這兩個文件,編譯器也找不到,不知何解。索性自己定義了。*/

  023.

  024.int main(int argc, char *argv[])

  025.{

  026.    int i, maxi, listenfd, connfd, sockfd;

  027.    int nready;

  028.    ssize_t n;

  029.    socklen_t clilen;

  030.    struct sockaddr_in servaddr, cliaddr;

  031.    struct hostent  *hp;

  032.    char buf[BUFSIZ];

  033.    struct pollfd client[OPEN_MAX]; /*用於poll函數第一個參數的數組*/

  034.

  035.    if( argc != 2 )

  036.    {

  037.        printf("Please input %s <hostname>\n", argv[0]);

  038.        exit(1);

  039.    }

  040.

  041.    //創建socket

  042.    if( (listenfd = socket(AF_INET, SOCK_STREAM,0)) < 0 )

  043.    {

  044.        printf("Create socket error!\n");

  045.        exit(1);

  046.    }

  047.

  048.    //設置服務器地址結構

  049.    bzero(&servaddr, sizeof(servaddr));

  050.    servaddr.sin_family = AF_INET;

  051.    if( (hp = gethostbyname(argv[1])) != NULL )

  052.    {

  053.        bcopy(hp->h_addr, (struct sockaddr*)&servaddr.sin_addr, hp->h_length);

  054.    }

  055.    else if(inet_aton(argv[1], &servaddr.sin_addr) < 0 )

  056.    {

  057.        printf("Input Server IP error!\n");

  058.        exit(1);

  059.    }

  060.    servaddr.sin_port = htons(SERVER_PORT);

  061.

062.    //綁定地址

  063.    if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0 )

  064.    {

  065.        printf("IPaddress bound failure!\n");

  066.        exit(1);

  067.    }

  068.

  069.    //開始監聽

  070.    listen(listenfd, LISTENQ);

  071.

  072.    client[0].fd = listenfd;         /*將數組中的第一個元素設置成監聽描述字*/

  073.

  074.    client[0].events = POLLIN;  /*將測試條件設置成普通或優先級帶數據可讀,此處書中為POLLRDNORM,

  075.                                      但是怎么也編譯不過去 ,編譯器就是找不到,所以就臨時改成了POLLIN這個條件,

  076.                                      希望以后能弄清楚。

  077.                                     */

  078.

  079.    for(i = 1;i < OPEN_MAX; ++i)     /*數組中的其它元素將暫時設置成不可用*/

  080.        client[i].fd = -1;

  081.    maxi = 0;

  082.

  083.    while(1)

  084.    {

  085.        nready = poll(client, maxi+1,INFTIM); //將進程阻塞在poll上

  086.        if( client[0].revents & POLLIN/*POLLRDNORM*/ ) /*先測試監聽描述字*/

  087.        {

  088.            connfd = accept(listenfd,(struct sockaddr*)&servaddr, &clilen);

  089.            for(i = 1; i < OPEN_MAX; ++i)

  090.                if( client[i].fd < 0 )

  091.                {

  092.                    client[i].fd = connfd;  /*將新連接加入到測試數組中*/

  093.                    client[i].events = POLLIN;//POLLRDNORM; /*測試條件普通數據可讀*/

  094.                    break;

  095.                }

  096.            if( i == OPEN_MAX )

  097.            {

  098.                printf("too many clients"); //連接的客戶端太多了,都達到最大值了

  099.                exit(1);

  100.            }

  101.

  102.            if( i > maxi )

  103.                maxi = i;  //maxi記錄的是數組元素的個數

  104.

  105.            if( --nready <= 0 )

  106.                continue;   //如果沒有可讀的描述符了,就重新監聽連接

  107.        }

  108.

  109.        for(i = 1; i <= maxi; i++)  /*測試除監聽描述字以后的其它連接描述字*/

  110.        {

  111.            if( (sockfd = client[i].fd) < 0) /*如果當前描述字不可用,就測試下一個*/

  112.                continue;

  113.

  114.            if(client[i].revents & (POLLIN/*POLLRDNORM*/ | POLLERR))/*如果當前描述字返回的是普通數據可讀或出錯條件*/

  115.            {

  116.                if( (n = read(sockfd, buf, MAXLINE)) < 0) //從套接口中讀數據

  117.                {

  118.                    if( errno == ECONNRESET) //如果連接斷開,就關閉連接,並設當前描述符不可用

  119.                    {

  120.                        close(sockfd);

  121.                        client[i].fd = -1;

  122.                    }

  123.                    else

  124.                        perror("read error");

  125.                }

  126.                else if(n == 0) //如果數據讀取完畢,關閉連接,設置當前描述符不可用

  127.                {

  128.                    close(sockfd);

  129.                    client[i].fd = -1;

  130.                }

  131.                else

  132.                    write(sockfd, buf, n); //打印數據

  133.

  134.                if(--nready <= 0)

  135.                    break;

  136.

  137.            }

  138.        }

  139.    }

  140.

  141.    exit(0);

  142.}

  注:本章內容摘自<Unix 網絡編程>第六章。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM