epoll模型简介(Linux)

本文介绍了epoll模型在IT技术中的优点,如高效事件通知、支持大规模并发、零拷贝技术以及内核用户空间共享,同时也提及了其局限性,如Linux特定、API复杂和多线程支持不足。详细展示了使用epoll进行网络编程的步骤。
摘要由CSDN通过智能技术生成

epoll模型的优点:

1. 高效的事件通知机制: epoll 使用事件驱动的方式,只在有事件发生时才触发通知,避免了轮询的开销,提高了效率。
2. 支持大规模并发: epoll 支持同时监视大量的文件描述符,适用于高并发的网络编程场景。
3. 支持水平触发和边缘触发模式: epoll 提供了水平触发( LT )和边缘触发( ET )两种模式,可以根据需求选择适合的模式。
4. 零拷贝技术: epoll 支持零拷贝技术,可以将数据从内核空间直接拷贝到用户空间,减少了数据复制的开销。
5. 内核空间和用户空间的共享: epoll 允许将文件描述符和事件信息存储在用户空间,减少了系统调用的次数,提高了性能。

epoll模型的缺点:

1. Linux 特有: epoll Linux 特有的事件通知机制,不支持在其他操作系统上使用。
2. API 复杂: epoll API 相对复杂,相比于传统的 select poll ,使用起来有一定的学习曲线。
3. 对多线程支持较差: epoll 在处理多线程编程时需要使用线程同步机制,比如互斥锁或信号量,编程复杂度较高。

使用epoll的步骤:

1. 创建 epoll 实例: 使用 epoll_create1 函数创建一个 epoll 实例。
2. 添加文件描述符: 使用 epoll_ctl 函数将需要监视的文件描述符添加到 epoll 实例中。
3. 等待事件: 使用 epoll_wait 函数等待事件的发生。
4. 处理事件: 根据事件的类型进行相应的处理,比如接受新连接、接收数据等。
5. 重复等待: 循环执行步骤 3 和步骤 4 ,实现持续的事件监听和处理。
6. 清理资源: 在程序退出前,关闭 epoll 实例并释放相关资源。

使用 epoll 模型可以提高网络编程的性能和并发能力,特别适用于需要处理大量并发连接的服务器端程序。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

#define MAX_EVENTS 10
#define PORT 54000
#define MAX_CLIENTS 100

int main() {
    int server_fd, client_fd, epoll_fd, event_count;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len;
    struct epoll_event event, events[MAX_EVENTS];

    // 创建 TCP socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址信息
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    // 绑定地址和端口
    if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(server_fd, MAX_CLIENTS) == -1) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 创建 epoll 实例
    if ((epoll_fd = epoll_create1(0)) == -1) {
        perror("epoll_create1");
        exit(EXIT_FAILURE);
    }

    // 添加监听的文件描述符到 epoll 实例中
    event.events = EPOLLIN;
    event.data.fd = server_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {
        perror("epoll_ctl");
        exit(EXIT_FAILURE);
    }

    std::cout << "Server listening on port " << PORT << std::endl;

    // 开始监听事件
    while (true) {
        event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (event_count == -1) {
            perror("epoll_wait");
            exit(EXIT_FAILURE);
        }

        for (int i = 0; i < event_count; ++i) {
            if (events[i].data.fd == server_fd) {
                // 有新的连接请求
                client_len = sizeof(client_addr);
                client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);
                if (client_fd == -1) {
                    perror("accept");
                    exit(EXIT_FAILURE);
                }

                std::cout << "New connection from " << inet_ntoa(client_addr.sin_addr) << std::endl;

                // 将新的客户端文件描述符添加到 epoll 实例中
                event.events = EPOLLIN | EPOLLET; // 设置为边缘触发模式
                event.data.fd = client_fd;
                if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) == -1) {
                    perror("epoll_ctl");
                    exit(EXIT_FAILURE);
                }
            }
            else {
                // 有客户端发送数据
                char buffer[1024];
                int bytes_received = recv(events[i].data.fd, buffer, sizeof(buffer), 0);
                if (bytes_received <= 0) {
                    // 客户端断开连接
                    std::cout << "Client disconnected" << std::endl;
                    close(events[i].data.fd);
                }
                else {
                    buffer[bytes_received] = '\0';
                    std::cout << "Received message from client: " << buffer << std::endl;
                }
            }
        }
    }

    // 关闭服务器 socket 和 epoll 实例
    close(server_fd);
    close(epoll_fd);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值