poll简介和源码
简介
poll跟select功能类似,可以监听多个文件描述符(以下简称fd),当监听的fd就绪时就可以open进行业务处理了,因此需要死循环查询监听的文件描述符是否就绪,两者的最主要的区别是select监听的fd有上限,poll没有,本章主要简单描述一下poll。
函数原型:
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);
fds通常是一个数组,nfds是它的数组大小,timeout超时时间单位是毫秒,poll会阻塞直到数组中的某些fd就绪时,返回它就绪fd的个数,当阻塞超时返回0,发生异常返回-1。作为web服务器,通常fds第0个元素监听的是web socket的fd,当第0个fd就绪时,就可以accpet获取到客服端的fd,然后放到第>0个位置,poll继续监听它。
struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ };
events是需要poll监听的事件,多个事件用 | 连接,revents是当监听的事件就绪时才有值。
例子:
//提供socket服务相关函数 #include "socklib.c" //业务逻辑处理 #include "handler.c" #include <poll.h> #include <signal.h> #define NFDSSIZE 1024 //初始化poll监听的fd为-1,意味着没有需要监听的fd void init_fd(struct pollfd *pfd); //等待poll事件就绪并打开fd,处理业务逻辑 void wait_poll(struct pollfd *pfd, nfds_t nfds, int sock); //收尾工作 void clearup(int signum); int sock; struct pollfd pfds[NFDSSIZE]; int main(int argc, char const *argv[]) { if (argc < 2) { exit_on_error("参数过少"); } sock = make_socket_server(atoi(argv[1])); if (sock == -1) { oops("make_socket_server()"); } //Ctrl+C时close sock fd signal(SIGINT, clearup); signal(SIGQUIT, clearup); for (size_t i = 0; i < NFDSSIZE; i++) { init_fd(&pfds[i]); } //第0个位置永远保存服务端sockfd,当sockfd就绪时就可以accpt了,第>0个位置存的客户端sockfd pfds[0].fd = sock; pfds[0].events = POLLIN | POLLRDNORM; pfds[0].revents = 0; while (1) { int retval = poll(pfds, NFDSSIZE, 5000); if (retval == -1) { perror("poll()"); } else if (retval == 0) { printf("poll timeout!\n"); }else { wait_poll(pfds, NFDSSIZE, sock); } } clearup(0); return EXIT_FAILURE; } void init_fd(struct pollfd *pfd) { pfd->fd = -1; pfd->events = 0; pfd->revents = 0; } void wait_poll(struct pollfd *pfds, nfds_t nfds, int sock) { int connect_fd; if (pfds[0].revents & POLLIN || pfds[0].revents & POLLRDNORM) { connect_fd = accept(sock, NULL, NULL); if (connect_fd == -1) { perror("accept()"); } else { printf("accept connect fd:%d\n", connect_fd); size_t i; for (i = 1; i < NFDSSIZE; i++) { //找到空闲的元素,connect fd保存到这个位置 if (pfds[i].fd == -1) { pfds[i].fd = connect_fd; pfds[i].events = POLLIN | POLLRDNORM; pfds[i].revents = 0; break; } } if (i == nfds) { printf("达到最大连接数!\n"); close(connect_fd); } } } else { for (size_t i = 1; i < NFDSSIZE; i++) { //connect fd read ready! if (pfds[i].fd != -1 && (pfds[i].revents & POLLIN || pfds[i].revents & POLLRDNORM)) { printf("connect fd %d available to read!\n", pfds[i].fd); handle_call(&pfds[i].fd); close(pfds[i].fd); init_fd(&pfds[i]); } } } } void clearup(int signum) { close(sock); exit(1); }
分类:
c
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)