我的网络观(3)——事件驱动的Reactor

简介: 本文探讨如何将Linux底层epoll高效封装为事件驱动的Reactor模型,涵盖连接管理、事件注册、回调处理等核心机制,并通过C语言代码详解服务器初始化、fd状态设置、读写回调及连接生命周期管理,提升高并发网络服务的可维护性与扩展性。

怎样才能更好的封装epoll

从epoll到reactor

既然epoll已经能够从底层支撑了大并发网络服务器的实现,接下来要做的就是怎么将epoll更好的封装,以使其更好的适配上层应用,上层往往不关注底层的连接和IO,更关注对不同就绪事件的处理,故而诞生了事件驱动的reactor

接下来梳理一遍reactor的工作流程,并展示它对各种功能接口的封装细节

int main(){
    unsigned short port = 2000;
//创建epoll
    epfd = epoll_create(1);

    int i = 0;
//开放监听MAX_PORT个端口
    for(i=0; i<MAX_PORT; i++){
    int sockfd = init_server(port+i);
    conn_list[sockfd].fd = sockfd;
    conn_list[sockfd].r_action.accept_callback = accept_cb;
    
    set_event(sockfd, EPOLLIN,1);
    }
//初始化计时器
    gettimeofday(&begin,NULL);
//mainloop
    while (1){
//创建用于接受就绪事件的集合
        struct epoll_event events[1024]={0};
//等待就绪事件
        int nready=epoll_wait(epfd, events, 1024, -1);
//逐个处理就绪事件,reactor的特点,按就绪事件类型来处理
        int i = 0;
        for (i=0; i<nready; i++ ){
            int connfd = events[i].data.fd;

            if((events[i].events & EPOLLIN)){
                conn_list[connfd].r_action.recv_callback(connfd);
            }

            if(events[i].events & EPOLLOUT){
                conn_list[connfd].send_callback(connfd);
            }

        }


    }

}



我们选择使用数组存储连接标识符fd,同时创建了一个结构体来存存储fd的所有信息

//连接标识符,读缓冲区,写缓冲区,三个回调函数
struct conn
{
    int fd;
    
    char rbuffer[BUFFER_LENGTH];
    int rlength;

    char wbuffer[BUFFER_LENGTH];
    int wlength;

    RCALLBACK send_callback;
//union一段内存,两个名字
    union{
    RCALLBACK recv_callback;
    RCALLBACK accept_callback;
    }r_action;
};

struct conn conn_list[CONN_SIZE] = {0};


封装对服务器的初始化功能

//初始化服务器,创建套接字并向内核申请把本机ip与端口同套接字绑定,设置套接字状态为监听,为后续连接做准备
int init_server(int port){
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
    servaddr.sin_port = htons(port); // 0-1023, 

    if (-1 == bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr))) {
        printf("bind failed: %s\n", strerror(errno));
    }

    listen(sockfd, 10);
    printf("listen finshed: %d\n", sockfd); // 3 
    
    return sockfd;
}

封装更改标识符设置功能

//连接标识符属性设置,可以实现监听和监听事件的修改
int set_event(int fd, int event,int flag){
    if(fd < 0 || fd >= CONN_SIZE){
        return -1;
    }
//flag用来区别设置监听还是修改监听事件
    if(flag){
        struct epoll_event ev;

        ev.events = event;
        ev.data.fd = fd;
        epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
        }else{
        struct epoll_event ev;
        ev.events = event;
        ev.data.fd = fd;
        epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);
        }
}

封装注册函数,初始化struct conn结构体实例

//注册,实现fd的回调函数,缓存空间的初始化
int event_register(int fd, int event){
    if(fd < 0 || fd >= CONN_SIZE){
        return -1;
    }
    conn_list[fd].fd = fd;
    conn_list[fd].r_action.recv_callback = recv_cb;
    conn_list[fd].send_callback = send_cb;

    memset(conn_list[fd].rbuffer, 0, BUFFER_LENGTH);
    conn_list[fd].rlength = 0;
 
    memset(conn_list[fd].wbuffer, 0, BUFFER_LENGTH);
    conn_list[fd].wlength = 0;

    set_event(fd, event,1);
}


回调函数——建立新连接

//建立新连接,在监听套接字监听到客户端发起连接
int accept_cb(int fd){
    if(fd < 0 || fd >= CONN_SIZE){
        return -1;
    }
    struct sockaddr_in  clientaddr;
    socklen_t len = sizeof(clientaddr);

    int clientfd = accept(fd, (struct sockaddr*)&clientaddr, &len);
    if(clientfd < 0) {
        return -1;
    }
    //每建立1000个连接打印一次总连接数,打印建立1000连接所需时间
        if(clientfd % 1000 == 0){
        struct timeval current;
        gettimeofday(&current,NULL);

        int time_used = TIME_SUB_MS(current,begin);
        memcpy(&begin,&current,sizeof(struct timeval));

        printf("accept finished: %d, timeused: %d\n",clientfd,time_used);
    }
    event_register(clientfd, EPOLLIN);

    return 0;

}



回调函数——接收数据

//接收数据,并将关注事件改为EPOLLOUT
int recv_cb(int fd){

    if(fd < 0 || fd >= CONN_SIZE){
        return -1;
    }
//将数据接收到rbuffer
    memset(conn_list[fd].rbuffer, 0, BUFFER_LENGTH );
    int count = recv(fd, conn_list[fd].rbuffer, BUFFER_LENGTH, 0);
    conn_list[fd].rlength = count; 
//disconnect
    if (count == 0) { 
        printf("client disconnect: %d\n", fd);
        close(fd);

        epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
                    
        return 0;
        }

        //printf("RECV: %s\n", conn_list[fd].rbuffer);
//将数据从rbuffer copy 到 wbuffer
#if 1
        conn_list[fd].wlength = conn_list[fd].rlength;
        memcpy(conn_list[fd].wbuffer, conn_list[fd].rbuffer, conn_list[fd].wlength);
#endif
//更换关注事件
        set_event(fd, EPOLLOUT,0);
        return count;
}

回调函数——发送数据

//将数据发送,并将fd关注事件调整为EPOLLIN
int send_cb(int fd){
    if(fd < 0 || fd >= CONN_SIZE){
        return -1;
    }
    int count = send(fd, conn_list[fd].wbuffer, conn_list[fd].wlength, 0);

    set_event(fd, EPOLLIN,0);
    
    return count;
}


目录
相关文章
|
3天前
|
存储 监控 Linux
我的网络观(2)——网络的IO多路复用机制
本文详解网络IO复用三大机制:SELECT(位图轮询,有FD数量限制)、POLL(事件分离,避免重复拷贝)与EPOLL(内核事件通知,高效无遍历)。对比一请求一线程模型的高开销,三者通过单线程管理多连接显著提升并发性能,是高性能服务器基石。
36 0
|
6天前
|
人工智能 JSON 安全
多店铺统一商品管理方案:拼多多+抖音电商自动上架的落地实践
本文介绍多店铺统一商品管理的AI+RPA落地方案:以“AI写代码、RPA跑代码”为核心,实现商品数据一源维护、跨平台自动上架、库存同步与智能自愈。支持拼多多/抖店等多平台差异化解析,全离线部署保安全,零代码搭建、AI诊断修复,显著降低店群运营重复劳动。
|
6天前
|
网络协议 C语言
我的网络观(1)——初学者的记录
本文详解如何用C语言实现“一请求一线程”TCP服务器:通过socket创建监听套接字,accept接收连接后为每个客户端创建独立线程,线程内以while循环持续recv/send,实现多客户端并发、双工、长连接通信,避免阻塞与串行等待。
51 0
|
1天前
|
云安全 安全 网络安全
|
1天前
|
JavaScript 安全 前端开发
Nodejs Brotli decoder 代码执行漏洞 (CVE-2026-111497)10629
Node.js发布安全更新修复Brotli解码器高危RCE漏洞(CVE-2026-111497),建议受影响版本用户立即升级。
1605 0
|
7天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
1305 28
|
3天前
|
存储 人工智能 自然语言处理
阿里云千问办公官网登录入口:qwenwork.cn网页版免下载,注册送2000积分、登录每日再送100积分
千问办公(QwenWork)是阿里巴巴推出的一站式AI办公平台,定位"不止于对话,更注重交付"。它基于千问大模型,具备任务拆解与多步骤自动执行能力,用户一句话即可完成PPT生成、数据分析、网页搭建、视频剪辑、信息调研等复杂任务,覆盖网页端、桌面端及钉钉生态。网页版免下载,访问qwenwork.cn注册即得2000积分,每日登录再送100积分。个人版免费起用,另有付费版与企业版可选。
|
12天前
|
存储 人工智能 安全
千问办公官网入口网页版登录:qwenwork.cn 注册送2000积分、登录送100积分
阿里云千问办公(QwenWork)是AI智能工作平台,支持一句话生成PPT、表格、网页、视频及数据分析。个人免费版送2000积分+每日登录赠100分,含1GB存储、5个发布页;企业版198元/席/月起。阿里千问办公QwenWork官网:https://t.aliyun.com/U/0VCTGt 阿里AI工作平台,一句话完成数据分析、PPT 生成、视频剪辑、网页搭建等复杂任务
|
7天前
|
人工智能 开发者
Qoder CN 大使计划正式开启|无限创造,等你一起
全年免费积分、优先内测、活动支持与更多共创机会,邀请用 Qoder 把想法变成现实的你。
615 6
|
9天前
|
安全 Linux 芯片
【万字长文】Ollama下载、安装、配置、使用保姆级教程(2026最新图解)
Ollama 是一款免费开源的本地大模型运行工具,支持 DeepSeek、Qwen 等主流模型,一条命令即可下载运行。2026 最新版 v0.35.1 官方安装包(1.47GB)已提供国内直连下载,纯本地、离线可用、无广告、无隐私泄露风险。
841 2