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;
}

优缺:

优点:

  1. 没有文件描述符个数限制(但是性能瓶颈很明显)

  2. 描述符个数小的场景下,推荐用poll,不用select

缺点:

  1. 就是慢,还是遍历的方式,文件描述符多了比select更差

  2. 相比于epoll,没有事件信息

Last updated