Poll 是 Linux 内核提供的一种 I/O 多路复用机制,允许单个进程/线程处理多个文件描述符(如套接字、管道等)的 I/O 事件。与 select
和 epoll
相比,poll
提供了一种相对简单的方式来监控多个文件描述符的状态变化。
select
,poll
的 API 更加简洁,不需要重新初始化文件描述符集合。epoll
高效,但 poll
在处理大量文件描述符时仍然比 select
表现更好。poll
在大多数类 Unix 系统上都有良好的支持。poll
会阻塞调用线程直到至少一个文件描述符准备好进行 I/O 操作。poll
可以立即返回,即使没有文件描述符准备好。应用场景:
以下是一个简单的 poll
使用示例,展示如何监控一个套接字的读事件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAX_EVENTS 10
int main() {
int sockfd, newsockfd, portno;
struct sockaddr_in serv_addr, cli_addr;
socklen_t clilen;
char buffer[256];
int n;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("ERROR opening socket");
exit(1);
}
memset((char *) &serv_addr, 0, sizeof(serv_addr));
portno = 8080;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR on binding");
exit(1);
}
listen(sockfd, 5);
clilen = sizeof(cli_addr);
struct pollfd fds[MAX_EVENTS];
fds[0].fd = sockfd;
fds[0].events = POLLIN;
while (1) {
int ret = poll(fds, MAX_EVENTS, -1);
if (ret < 0) {
perror("poll error");
break;
}
if (fds[0].revents & POLLIN) {
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
perror("ERROR on accept");
continue;
}
fds[1].fd = newsockfd;
fds[1].events = POLLIN;
}
for (int i = 1; i < MAX_EVENTS; i++) {
if (fds[i].revents & POLLIN) {
n = read(fds[i].fd, buffer, 255);
if (n < 0) {
perror("ERROR reading from socket");
close(fds[i].fd);
fds[i] = fds[MAX_EVENTS - 1];
i--;
} else {
buffer[n] = '\0';
printf("Here is the message: %s\n", buffer);
}
}
}
}
close(sockfd);
return 0;
}
问题1:poll
返回错误码
原因:可能是由于系统资源不足、文件描述符无效或其他系统级错误。
解决方法:
perror
或 strerror
打印详细的错误信息以便调试。问题2:poll
超时
原因:设置的超时时间太短或者系统负载过高导致无法及时响应。
解决方法:
通过以上内容,你应该对 Linux poll
驱动有了全面的了解,并能够在实际开发中灵活运用。
领取专属 10元无门槛券
手把手带您无忧上云