linux 下 poll 編程


  poll 與 select 很類似,都是對描述符進行遍歷,查看是否有描述符就緒。如果有就返回就緒文件描述符的個數將。poll 函數如下:

  #include <poll.h>

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

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

  struct pollfd

  {

    int fd;

    short events;//關心 fd 上發生的事件

    short revents;//fd 實際上上發生的事件

  }

  要測試的條件由 events 成員指定,函數在相應的 revents 成員中返回該描述符的狀態(每個描述符都有兩個變量,一個為調用值,另一個為返回結果,從而避免值-結果參數)這兩個成員中的每一個都由指定某個特定條件的一位或多位組合而成。下標列出指定 events 標志以及測試 revents 標志的一些常值。

 

  ----------------------------+---------------------------------------+---------------------------------------+----------------------------------------+

  常量         |  能做為 events 的輸入嗎?    | 能作為revents 的結果嗎? | 說明             |

  ----------------------------+---------------------------------------+---------------------------------------+----------------------------------------+

  POLLIN      |    能         |       能      |  普通或者優先級帶數據可讀    |

  POLLRDNORM    |    能         |       能      |  普通數據可讀          |

  POLLRDBAND          |    能         |       能      |  優先級帶數據可讀        |

  POLLPRI      |    能         |       能      |  高優先級數據可讀      |

  ----------------------------+---------------------------------------+---------------------------------------+----------------------------------------+

  POLLOUT       |    能         |       能      | 普通數據可寫           |

  POLLWRNORM   |    能         |       能      | 普通數據可寫        |

  POLLWRBAND    |    能         |       能      | 優先級帶數據可寫      |

  ----------------------------+---------------------------------------+--------------------------------------+-----------------------------------------+

  POLLERR       |              |       能      | 發生錯誤          |

  POLLHUP       |              |       能      | 發生掛起          |

  POLLNVAL                |              |         能      | 描述字不是一個打開的文件     |

  -----------------------------+--------------------------------------+---------------------------------------+----------------------------------------+

  第二個參數 nfds 制定數組中元素個數。第三個參數指定 poll 函數返回前等待多長時間。 INFTIM 表示永遠等待, 0 代表立即返回, > 0 等待指定數目的秒數。

  1 #include <sys/socket.h>
  2 #include <netinet/in.h>
  3 #include <stdio.h>
  4 #include <error.h>
  5 #include <errno.h>
  6 #include <unistd.h>
  7 #include <string.h>
  8 #include <stdlib.h>
  9 #include <sys/wait.h>
 10 #include <limits.h>
 11 #include <poll.h>
 12 #include <sys/stropts.h>
 13 #include <signal.h>
 14 #define MAXLINE 5
 15 #define OPEN_MAX 1024
 16 #define SA struct sockaddr
 17 
 18 
 19 int main()
 20 {
 21     int listenfd, connfd, sockfd, i, maxi;
 22     int nready;
 23     socklen_t clilen;
 24     ssize_t n;
 25     char buf[MAXLINE];
 26     struct pollfd client[OPEN_MAX];
 27     struct sockaddr_in servaddr, cliaddr;
 28     //創建監聽套接字
 29     if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 30     {
 31         printf("socket() error!");
 32         exit(0);
 33     }
 34     //先要對協議地址進行清零
 35     bzero(&servaddr,sizeof(servaddr));
 36     //設置為 IPv4 or IPv6
 37     servaddr.sin_family = AF_INET;
 38     //綁定本地端口號
 39     servaddr.sin_port    = htons(9805);
 40     //任何一個 IP 地址,讓內核自行選擇
 41     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 42     //綁定套接口到本地協議地址
 43     if(bind(listenfd, (SA *) &servaddr,sizeof(servaddr)) < 0)
 44     {
 45         printf("bind() error!");
 46         exit(0);
 47     }
 48     //服務器開始監聽
 49     if(listen(listenfd,5) < 0)
 50     {
 51         printf("listen() error!");
 52         exit(0);
 53     }
 54     client[0].fd = listenfd;
 55     client[0].events = POLLRDNORM;//關心監聽套機字的讀事件
 56     for(i = 1; i < OPEN_MAX; ++i)
 57     {
 58         client[i].fd = -1;
 59     }
 60     maxi = 0;
 61     for(;;)
 62     {
 63         nready = poll(client, maxi + 1, -1);
 64         if(client[0].revents & POLLRDNORM)
 65         {
 66             clilen = sizeof(cliaddr);
 67             //accept 的后面兩個參數都是值-結果參數,他們的保留的遠程連接電腦的信息,如果不管新遠程連接電腦的信息,可以將這兩個參數設置為 NULL
 68             connfd = accept(listenfd, (SA *) &cliaddr, &clilen);
 69             if(connfd < 0)
 70             {
 71                 continue;
 72             }
 73             for(i = 1; i < OPEN_MAX; ++i)
 74             {
 75                 if(client[i].fd < 0)
 76                     client[i].fd = connfd;
 77                 break;
 78             }
 79             if(i == OPEN_MAX)
 80             {
 81                 printf("too many clients");
 82                 exit(0);
 83             }
 84             client[i].events = POLLRDNORM;
 85             if(i > maxi)
 86             {
 87                 maxi = i;
 88             }
 89             if(--nready <=0 )
 90                 continue;
 91         }
 92         for(i = 1; i < OPEN_MAX; ++i)
 93         {
 94             if((sockfd = client[i].fd) < 0)
 95             {
 96                 continue;
 97             }
 98             if(client[i].revents & POLLRDNORM | POLLERR)
 99             {
100                 if((n = read(sockfd, buf, MAXLINE)) < 0)
101                 {
102                     if(errno == ECONNRESET)
103                     {
104                         close(sockfd);
105                         client[i].fd = -1;
106                     }
107                     else
108                     {
109                         printf("read error!\n");
110                     }
111                 }
112                 else if(n == 0)
113                 {
114                     close(sockfd);
115                     client[i].fd = -1;
116                 }
117                 else
118                 {
119                     write(sockfd, buf,  n);
120                 }
121                 if(--nready <= 0)
122                     break;
123             }
124         }
125     }
126 }

  配合 linux 下 select 編程 就是一個完整的客戶端/服務器端代碼了,運行結果截圖如下:

  客戶端:

  

  服務器端:

    

    


免責聲明!

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



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