poll 示例
相比于select,poll扩展了文件描述符的个数,但其还是使用遍历所有描述符的方式检查事件触发
code
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <vector>
using namespace std;
#define PORT 8888
#define MAX_EVENTS 1024
int main() {
int server_fd;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[1024] = {0};
vector<pollfd> fds;
// 创建套接字
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(PORT);
// 绑定套接字
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);
}
// 初始化pollfd数组
pollfd fd;
fd.fd = server_fd;
fd.events = POLLIN;
fds.push_back(fd);
while (true) {
int num_events = poll(fds.data(), fds.size(), -1); // -1 为无线阻塞,0为不阻塞,其他值表示阻塞的时间
if (num_events < 0) {
perror("poll");
exit(EXIT_FAILURE);
}
for (int i = 0; i < num_events; ++i) {
if (fds[i].revents & POLLIN) {
if (fds[i].fd == server_fd) {
// 有新的连接
int new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen);
if (new_socket < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
// 将新连接添加到pollfd数组
pollfd new_fd;
new_fd.fd = new_socket;
new_fd.events = POLLIN;
fds.push_back(new_fd);
} else {
// 有数据可读
int bytes_read = read(fds[i].fd, buffer, 1024);
if (bytes_read <= 0) {
// 连接关闭或出错
close(fds[i].fd);
fds.erase(fds.begin() + i);
--i; // 调整索引
} else {
// 处理接收到的数据
cout << "Client: " << buffer << endl;
// ...
}
}
}
}
}
return 0;
}
优缺:
优点:
没有文件描述符个数限制(但是性能瓶颈很明显)
描述符个数小的场景下,推荐用poll,不用select
缺点:
就是慢,还是遍历的方式,文件描述符多了比select更差
相比于epoll,没有事件信息
Last updated