poll 函数

2014-12-12 15:28:09   最后更新: 2014-12-12 21:10:27   访问数量:931




poll 与 select 函数类似,但在处理流设备时,poll 可以提供额外的信息

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

 

定义于 poll.h 中

若超时返回0,出错返回-1,否则返回就绪描述符数目

fdarray

第一个参数是一个结构体数组头指针,数组的每个元素是一个 pollfd 结构:

struct pollfd { int fd; short events; short revents; };

 

要测试的条件由 events 成员指定,函数调用结束后在 revents 成员中返回描述符状态

与 select 的值-结果参数不同,这样做无须每次调用后重新为参数赋值

 

events、revents 常量

events、revents 可选常量
常量值events可选revents可选说明
输入处理   
POLLINYY普通或优先级带数据可读
POLLRDNORMYY普通数据可读
POLLRDBANDYY优先级带数据可读
POLLPRIYY高优先级数据可读
输出处理   
POLLOUTYY普通数据可写
POLLWRNORMYY普通数据可写
POLLWRBANDYY优先级带数据可写
出错处理   
POLLERR Y发生错误
POLLHUP Y发生挂起
POLLNVAL Y描述符不是一个打开的文件

nfds

参数个数由 nfds 参数指定

Unix98 定义了名为 nfds_t 的新的数据类型,用来指定该值

timeout

timeout 参数指定 poll 函数返回前等待多长时间

poll函数timeout参数取值
取值说明
INFTIM永远等待
0立即返回,不阻塞进程
> 0等待指定毫秒数

  • 需要注意的是,部分系统将 INFTIM 宏定义在 sys/stropts.h 中,其余系统按照POSIX规范定义在 poll.h 中

revents 的返回值

poll 函数的许多种调用方式可能会返回相同的条件,这是一个历史问题

下列条件可以引起 poll 返回特定的 revents:

  • 所有正规 TCP 数据和 UDP 数据都被认为是普通数据
  • TCP 带外数据被认为是优先级带数据
  • 当 TCP 连接的读半部分关闭时,比如接收到对端的 FIN,读操作将返回0,并被认为是普通数据
  • TCP 连接存在错误既可以被认为是普通数据,也可以认为是 POLLERR,随后读操作将返回-1,errno 被设置为合适的值
  • 在监听套接字上有新的连接可用既可以认为是普通数据也可以认为是优先级数据,大多数实现视之为普通数据
  • 非阻塞式 connect 的完成被认为是使相应套接字可写
  • 如果 pollfd 结构的 fd 成员为-1,则 poll 函数会忽略该结构中的 events 成员,并将 revents 成员置为 0

poll 避免了 select 使用值-结果参数带来的复杂度,并且不再限制每个进程最大描述符数目(FD_SETSIZE),但是支持 select 的系统要比支持 poll 的系统多,并且,如果你需要在操作中处理信号阻塞,或实现更高的时间分辨率,就只能使用 pselect

/* * author: liuzeyu * date: 2014-12-12 * file: main.c */ #include "function/function.h" int main () { int listenfd, connfd, sockfd, nready, n, i, maxi=0; socklen_t clilen; struct pollfd client[OPEN_MAX]; struct sockaddr_in cliaddr; char buf[MAXLINE]; listenfd = get_listenfd(); client[0].fd = listenfd; client[0].events = POLLRDNORM; for (i=1; i<OPEN_MAX; ++i) client[i].fd = -1; while (1) { nready = poll(client, maxi+1, 0); if (nready < 0) { perror("poll"); exit(-1); } if (client[0].revents & POLLRDNORM) { clilen = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen); if (connfd < 0) { perror("accept"); exit(-1); } for (i=1; i<OPEN_MAX; ++i) { if (client[i].fd == -1) { client[i].fd = connfd; client[i].events = POLLRDNORM; break; } } if (i == OPEN_MAX) { printf ("too many clients\n"); continue; } if (i > maxi) maxi = i; if (--nready <= 0) continue; } for (i=1; i <= maxi; ++i) { if ((sockfd = client[i].fd) < 0) continue; if (client[i].revents & (POLLRDNORM | POLLERR)) { if ((n = read(sockfd, buf, MAXLINE)) < 0) { if (errno == ECONNRESET) // 客户端主动关闭 { close(sockfd); client[i].fd = -1; } else { perror("read"); exit(-1); } } else if (n == 0) { close(sockfd); client[i].fd = -1; } else { writen(sockfd, buf, n); } if (--nready <= 0) break; } } } }

 

 






读书笔记      技术帖      linux      unix      network      cpp      unp      unix网络编程      网络编程      龙潭书斋      poll      c     


京ICP备15018585号