巩义专业网站建设公司首选,c 做网站怎么显示歌词,深圳品牌手表有哪些,设计公司logo需要多少钱poll() 的机制与 select() 类似#xff0c;与 select() 在本质上没有多大差别#xff0c;管理多个描述符也是进行轮询#xff0c;根据描述符的状态进行处理#xff0c;但是 poll() 没有最大文件描述符数量的限制#xff08;但是数量过大后性能也是会下降#xff09;。 p… poll() 的机制与 select() 类似与 select() 在本质上没有多大差别管理多个描述符也是进行轮询根据描述符的状态进行处理但是 poll() 没有最大文件描述符数量的限制但是数量过大后性能也是会下降。 poll() 和 select() 同样存在一个缺点就是包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间而不论这些文件描述符是否就绪它的开销随着文件描述符数量的增加而线性增大。 函数原型分析 int poll(struct pollfd *fds, nfds_t nfds, int timeout); fds监听的文件描述符【数组】 struct pollfd { int fd 待监听的文件描述符 short events 待监听的文件描述符对应的监听事件 取值POLLIN、POLLOUT、POLLERR short revnets 传入时 给0。如果满足对应事件的话 返回 非0 --POLLIN、POLLOUT、POLLERR } nfds: 监听数组的实际有效监听个数。 timeout: 0: 超时时长。单位毫秒。 -1: 阻塞等待 0 不阻塞 返回值返回满足对应监听事件的文件描述符总个数。 优缺点 优点 自带数组结构。 可以将 监听事件集合 和 返回事件集合 分离。 拓展 监听上限。 超出 1024限制。 缺点 不能跨平台。 Linux 无法直接定位满足监听事件的文件描述符 编码难度较大。 代码实例
/* server.c */
#include stdio.h
#include stdlib.h
#include string.h
#include netinet/in.h
#include arpa/inet.h
#include poll.h
#include errno.h
#include wrap.h#define MAXLINE 80
#define SERV_PORT 6666
#define OPEN_MAX 1024int main(int argc, char *argv[])
{int i, j, maxi, listenfd, connfd, sockfd;int nready;ssize_t n;char buf[MAXLINE], str[INET_ADDRSTRLEN];socklen_t clilen;struct pollfd client[OPEN_MAX];struct sockaddr_in cliaddr, servaddr;listenfd Socket(AF_INET, SOCK_STREAM, 0);bzero(servaddr, sizeof(servaddr));servaddr.sin_family AF_INET;servaddr.sin_addr.s_addr htonl(INADDR_ANY);servaddr.sin_port htons(SERV_PORT);Bind(listenfd, (struct sockaddr *)servaddr, sizeof(servaddr));Listen(listenfd, 20);client[0].fd listenfd;client[0].events POLLRDNORM; /* listenfd监听普通读事件 */for (i 1; i OPEN_MAX; i)client[i].fd -1; /* 用-1初始化client[]里剩下元素 */maxi 0; /* client[]数组有效元素中最大元素下标 */for ( ; ; ) {nready poll(client, maxi1, -1); /* 阻塞 */if (client[0].revents POLLRDNORM) { /* 有客户端链接请求 */clilen sizeof(cliaddr);connfd Accept(listenfd, (struct sockaddr *)cliaddr, clilen);printf(received from %s at PORT %d\n,inet_ntop(AF_INET, cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));for (i 1; i OPEN_MAX; i) {if (client[i].fd 0) {client[i].fd connfd; /* 找到client[]中空闲的位置存放accept返回的connfd */break;}}if (i OPEN_MAX)perr_exit(too many clients);client[i].events POLLRDNORM; /* 设置刚刚返回的connfd监控读事件 */if (i maxi)maxi i; /* 更新client[]中最大元素下标 */if (--nready 0)continue; /* 没有更多就绪事件时,继续回到poll阻塞 */}for (i 1; i maxi; i) { /* 检测client[] */if ((sockfd client[i].fd) 0)continue;if (client[i].revents (POLLRDNORM | POLLERR)) {if ((n Read(sockfd, buf, MAXLINE)) 0) {if (errno ECONNRESET) { /* 当收到 RST标志时 *//* connection reset by client */printf(client[%d] aborted connection\n, i);Close(sockfd);client[i].fd -1;} else {perr_exit(read error);}} else if (n 0) {/* connection closed by client */printf(client[%d] closed connection\n, i);Close(sockfd);client[i].fd -1;} else {for (j 0; j n; j)buf[j] toupper(buf[j]);Writen(sockfd, buf, n);}if (--nready 0)break; /* no more readable descriptors */}}}return 0;
}read 函数 read 函数返回值 0: 实际读到的字节数 0 socket中表示对端关闭。close -1 如果 errno EINTR 被异常终端。 需要重启。 如果 errno EAGIN 或 EWOULDBLOCK 以非阻塞方式读数据但是没有数据。 需要再次读。 如果 errno ECONNRESET 说明连接被 重置。 需要 close移除监听队列。 错误。 了解突破1024 文件描述符限制 cat /proc/sys/fs/file-max -- 当前计算机所能打开的最大文件个数。 受硬件影响。 ulimit -a -- 当前用户下的进程默认打开文件描述符个数。 缺省为 1024 修改 打开 sudo vi /etc/security/limits.conf 写入 * soft nofile 65536 -- 设置默认值可直接借助命令修改【注销用户使其生效】 * hard nofile 100000 -- 命令修改上限。