您好,登錄后才能下訂單哦!
一、poll
poll的實現和select非常相似,只是描述fd集合的方式不同,poll使用pollfd結構而不是select的fd_set結構,其他的都差不多。
二、poll相關函數
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
//fds: pollfd結構體
events: 要監視的事件
revents: 已經發生的事件, 設置標志 來反映相關條件的存在
常量 說明
POLLIN 普通或優先級帶數據可讀
POLLRDNORM 普通數據可讀
POLLRDBAND 優先級帶數據可讀
POLLPRI 高優先級數據可讀
POLLOUT 普通數據可寫
POLLWRNORM 普通數據可寫
POLLWRBAND 優先級帶數據可寫
// 只能作為描述字的返回結果存儲在revents中
POLLERR 發生錯誤
POLLHUP 發生掛起
POLLNVAL 描述字不是一個打開的文件
struct pollfd { int fd; /* 文件描述符 */ short events; /* 請求的事件 */ short revents; /* 返回的事件 */ };
//nfds: 要監視的描述符的數目
//timeout:指定poll在返回前沒有接收事件時應該等待的時間【單位:ms】。
INFTIM: 永不超時
0 :立即返回
>0: 等待指定的時間
2、特點:
pollfd并沒有最大數量限制(但是數量過大后性能也是會下降)。
和select函數一樣,poll返回后,需要輪詢pollfd來獲取就緒的描述符。
select和poll都需要在返回后,通過遍歷文件描述符來獲取已經就緒的socket。事實上,同時連接的大量客戶端在一時刻可能只有很少的處于就緒狀態,因此隨著監視的描述符數量的增長,其效率也會線性下降。
三、poll 服務器
#include <stdio.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h> #include<netinet/in.h> #include<unistd.h> #include<string.h> #include<errno.h> #include<sys/select.h> #include<sys/poll.h> #define _BACKLOG_ 5 #define _MAX_NUM_ 64 void usage(const char *proc) { printf("Usage: %s [ip][port]\n",proc); } static int startup(const char *ip,const int port) { int sock=socket(AF_INET,SOCK_STREAM,0); if(sock < 0) { perror("socket"); exit(1); } int opt=1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(port); local.sin_addr.s_addr=inet_addr(ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local)) < 0) { perror("bind"); exit(2); } if(listen(sock,_BACKLOG_) < 0) { perror("listen"); exit(3); } return sock; } static int poll_server(int listen_sock) { struct sockaddr_in client; socklen_t len=sizeof(client); struct pollfd fds[_MAX_NUM_]; fds[0].fd=listen_sock; fds[0].events=POLLIN; fds[0].revents=0; size_t i=0; for(;i<_MAX_NUM_;++i) { fds[i].fd=-1; fds[i].events=0; fds[i].revents=0; } int max_fd=1; int timeout=5000; while(1) { switch(poll(fds,max_fd,timeout)) { case -1://error perror("poll"); break; case 0://timeout printf("poll timeout"); break; default://normal { for(i=0;i<_MAX_NUM_;++i) { //is listen events ready? if(fds[i].fd == listen_sock && fds[i].revents == POLLIN) { int accept_sock=accept(listen_sock,(struct sockaddr*)&client,&len); if(accept_sock < 0) { perror("accept"); continue; } printf("get a client...[ip: %s][port: %d]\n",\ inet_ntoa(client.sin_addr),ntohs(client.sin_port)); for(i=0;i<_MAX_NUM_;++i) { if(fds[i].fd == -1) { fds[i].fd=accept_sock; fds[i].events=POLLIN; max_fd++; break; } } if(i == _MAX_NUM_) { close(accept_sock); } } else if(fds[i].fd > 0 && fds[i].revents == POLLIN) { char buf[1024]; ssize_t _size=read(fds[i].fd,buf,sizeof(buf)-1); if(_size > 0)//read success { buf[_size]='\0'; printf("Client # %s",buf); } else if(_size == 0)//client close { printf("clint close...\n"); struct pollfd tmp=fds[i]; fds[i]=fds[max_fd-1]; close(fds[max_fd-1].fd); fds[max_fd-1].fd=-1; fds[max_fd-1].events=0; fds[max_fd-1].revents=0; --max_fd; } } else {} } } break; } } return 0; } int main(int argc,char *argv[]) { if(argc != 3) { usage(argv[0]); return 1; } char *ip=argv[1]; int port=atoi(argv[2]); int listen_sock=startup(ip,port); poll_server(listen_sock); close(listen_sock); return 0; }
總結:
poll在返回后,需要通過遍歷文件描述符來獲取已經就緒的socket從而進行下一步操作;而且使用完監聽套接字后,都需要進行關閉。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。