栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Epoll编程笔记

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Epoll编程笔记

个人作品,未经允许禁止转载!!! 解决IO问题的编程模型及特点 1.阻塞等待

缺点:一个fd等待时,其他fd无法被监听

2.多线程阻塞等待

缺点:一个fd占用一个线程,线程过多,效率很低

3.非阻塞、忙轮询

缺点:无效轮询占用大量CPU时间

4.Select

缺点:能够打开的fd数量受内核限制,如需修改,需要编译内核。效率较低,每次需要遍历fd数组,复杂度和最大fd数量相同

5.Epoll

优点:用红黑树管理fd,每次返回可以读写或者发生其他事件的fd,大部分情况下效率高于select。

缺点:Linux系统的API。当每个连接都非常活跃时,效率会低于select

Epoll API(Doc地址:epoll document) 1.头文件:
#include 
2.创建Epoll
//size是Epoll最大监听的fd的数量,对应内部红黑树的最大节点数
//返回一个epoll的描述符 epoll fd
int epoll_create(int size);
3.设置Epoll
 epoll_data_t data; 
}
其中,events为监听的事件,可以是:
EPOLLIN 可读
EPOLLOUT 可写
EPOLLRDHUP socket另一端关闭连接
POLLPRI 预料之外的错误,很少用,参见https://man7.org/linux/man-pages/man2/poll.2.html
EPOLLERR 发生错误,默认开启,无法关闭,所以也没必要传入
EPOLLHUP 描述符被挂起
EPOLLET 边沿触发事件。默认情况下是水平触发
等

typedef union epoll_data {
    void *ptr;
    int fd;
    uint32_t u32;
    uint64_t u64;
} epoll_data_t;
data是一个结构体,可以是用户自行传入的任意数据的指针(这是实现Reactor模式的关键)
*/
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
4.监听Epoll事件
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
5.Epoll编程常用步骤
#define MAX_FD 1024
//创建 epoll
int epfd = epoll_crete(MAX_FD);

//将监听的socket添加进 epoll 中
epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &event);

while (1) {
    //阻塞等待 epoll 中 的fd 触发
    int active_cnt = epoll_wait(epfd, events, 1000, -1);
    # 对返回的fd进行
    for (i = 0 ; i < active_cnt; i++) {
        //如果监听的fd触发,那么accept请求,并将fd加入epoll
        if (evnets[i].data.fd == listen_fd) {
        }
        //如果其他fd触发,则进行读写
        else if (events[i].events & EPOLLIN) {
        }
        else if (events[i].events & EPOLLOUT) {
        }
    }
}
Epoll回显服务器
服务器端
#include 
#include 
#include 
#include 

#define SERVER_PORT 9998
#define MAX_PENDING_ConNECTION 1024
#define EPOLL_MAX_FD (1024*1024)
#define MAX_BUFFER_SIZE (1024*1024)

using namespace std;
bool running = true;
int main(int argc, char* argv[]){
    int32_t listen_fd = 0, epoll_fd = 0;
    sockaddr_in server_addr{};

    // 创建监听套接字
    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    // 绑定端口
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(SERVER_PORT);
    bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    // 监听
    listen(listen_fd, MAX_PENDING_CONNECTION);

    // 创建epoll
    epoll_fd = epoll_create(EPOLL_MAX_FD);
    if (epoll_fd < 0){
        perror("Epoll create failed");
        return -1;
    }
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = listen_fd;
    // 将监听套接字加入epoll
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event) < 0){
        perror("Epoll CTL add listen fd");
        return -1;
    }
    struct epoll_event *events = new struct epoll_event[EPOLL_MAX_FD];
    int client_fd, active_fd;
    sockaddr_in client_addr{};
    char buffer[MAX_BUFFER_SIZE];
    while(running){
        // 等待epoll事件触发
        active_fd = epoll_wait(epoll_fd, events ,EPOLL_MAX_FD, -1);

        // 遍历epoll
        for (int i=0; i %s", buffer);
                    write(client_fd, buffer, n);
                }
            }
            // 套接字可写事件,没有监听,也不处理
            else if (events[i].events & EPOLLOUT){
                printf("Send Data -> Epoll out end! n");
            }
        }
    }
    close(epoll_fd);
    close(listen_fd);
    return 0;
}
客户端
#include 
#include 
#include 
#include 
#include 
#include 

#define MAX_BUFFER_SIZE (1024*1024)
#define SERVER_PORT 9998
int main(int argc, char* argv[]) {
    int sockfd;
    char buffer[MAX_BUFFER_SIZE];

    struct sockaddr_in server_addr{};
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        perror("socket");
        return -1;
    }
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    if (inet_pton(AF_INET, "0.0.0.0", &server_addr.sin_addr) <= 0){
        perror("inet_pton");
        return -1;
    }

    if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){
        perror("connect");
        return -1;
    }

    int opts = 0;
    opts = fcntl(sockfd, F_GETFL);
    opts = opts | O_NONBLOCK;
    fcntl(sockfd, F_SETFL);

    char input[1024];

    while(fgets(input, 1024, stdin) != nullptr){
        printf("Sending -> %s", input);
        int n = send(sockfd, input, strlen(input), 0);
        if (n < 0){
            perror("send");
            continue;
        }
        usleep(500000);
        n = read(sockfd, buffer, MAX_BUFFER_SIZE);
        if (n <= 0){
            perror("read");
            return -1;
        }
        else{
            buffer[n] = '';
            printf("Recv <- %s", buffer);
            continue;
        }
    }
    close(sockfd);
    return 0;
}

运行服务器和客户端后,从终端向客户端输入即可看到现象。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/309310.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号