poll
是 Linux 系统中用于 I/O 多路复用的一个系统调用,它允许单个进程/线程处理多个文件描述符的 I/O 事件。与 select
和 epoll
相比,poll
提供了更简洁的接口,并且在处理大量文件描述符时性能较好。
poll
系统调用通过一个 pollfd
结构体数组来监视多个文件描述符。每个 pollfd
结构体包含以下字段:
fd
:要监视的文件描述符。events
:感兴趣的事件,如读就绪(POLLIN)、写就绪(POLLOUT)等。revents
:实际发生的事件,由内核在调用返回时设置。select
,poll
的接口更简洁,不需要重新初始化文件描述符集合。poll
没有像 select
那样的文件描述符数量限制。poll
的性能优于 select
。poll
主要用于需要同时监视多个文件描述符(如套接字、管道等)的场景,常见于网络服务器编程。
以下是一个简单的 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 server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
// 创建套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 绑定套接字
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
// 监听连接
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
struct pollfd fds[MAX_EVENTS];
fds[0].fd = server_fd;
fds[0].events = POLLIN;
while (1) {
int ret = poll(fds, MAX_EVENTS, -1);
if (ret < 0) {
perror("poll");
exit(EXIT_FAILURE);
}
for (int i = 0; i < MAX_EVENTS; i++) {
if (fds[i].revents & POLLIN) {
if (fds[i].fd == server_fd) {
// 接受新连接
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
fds[1].fd = new_socket;
fds[1].events = POLLIN;
} else {
// 处理读事件
char buffer[1024] = {0};
read(fds[i].fd, buffer, 1024);
printf("Received message: %s\n", buffer);
}
}
}
}
return 0;
}
epoll
,它在处理大量文件描述符时性能更好。poll
时,可以设置超时时间,以避免无限期等待。poll
时,可以设置超时时间,以避免无限期等待。通过以上示例和说明,你应该能够理解 poll
的基本用法及其在实际应用中的优势和使用场景。
领取专属 10元无门槛券
手把手带您无忧上云