网络编程 -- Reactor模型学习

前言

Reactor 反应器基于IO多路复用和回调函数的原理而创造出,用于处理高并发的服务器框架。


一、Reactor模式介绍

  • 网络编程模型大体上以下几种:Reactor,Proactor,Asynchronous, Completion Token, and Acceptor-Connector.但是本文主要介绍最主流的Reactor模型。通常的网络编程模式处理过程为initiate => receive => demultiplex => dispatch => process events。但是Reactor模型可以借助I/O多路复用作为并发事件驱动(event-driven)的程序基础,即将整个事件驱动模型作为一个状态机,包含了状态(state), 输入事件(input-event), 状态转移(transition), 状态转移即状态到输入事件的一组映射。通过I/O多路复用的技术检测事件的发生,并根据具体的事件(通常为读写),进行不同的操作,即状态转移。
  • Reactor模式是一种典型的事件驱动的编程模型,Reactor逆置了程序处理的流程,其基本的思想即为Hollywood Principle— 'Don't call us, we'll call you'.普通的函数处理机制为:调用某函数-> 函数执行, 主程序等待阻塞-> 函数将结果返回给主程序-> 主程序继续执行。
  • Reactor事件处理机制为:主程序将事件以及对应事件处理的方法在Reactor上进行注册, 如果相应的事件发生,Reactor将会主动调用事件注册的接口,即 回调函数. libevent即为封装了epoll并注册相应的事件(I/O读写,时间事件,信号事件)以及回调函数,实现的事件驱动的框架。
  • Reactor事件处理机制的编程模型也在Redis中也得到了很好的运用,Redis中基于I/O多路复用(mutiplexing) 开发Reactor事件处理机制,监听多个套接字的AE_READABLE读事件和AE_WRITABLE写事件。读事件绑定读操作和具体执行命令的操作函数,写事件绑定命令回复的操作函数。
    Reactor程序框架示意图

二、Reactor原理

1. Reactor架构

Reactor简单示意图
Reactor架构模式允许事件驱动的应用通过多路分发的机制去处理来自不同客户端的多个请求。
在这里插入图片描述
上图为Reactor核心事件处理流程,主要是以下几个关键组件

  • 事件(事件源)
    linux系统上handler作为注册在特定事件上的程序,而事件通常为I/O事件,主要是由操作系统触发。
  • Reactor(反应器)
    Reactor为事件管理的接口,内部主要使用event demultiplexer注册,注销事件。然后运行事件循环,当有事件进入"就绪"状态时,调用注册事件的回调函数处理。
  • Event Handler(事件处理程序)
    事件处理程序提供了一组接口,在Reactor相应的事件发生时调用,执行相应的事件处理,通常会绑定一个有效的handler。
  • Synchronous event demultiplexer(事件多路分发机制)
    事件多路分发机制通常是由系统的I/O多路复用实现的。 程序首先将handler(事件源)以及对应的事件注册到event demultiplexer上;当有事件到达时,event demultiplexer就会发出通知,通知Reactor调用事件处理程序进行处理。

三、Reactor实现

1.React结构体

reactor 结构体:

typedef struct event_node{
    int fd;
    int events;
    int status;
    void* arg;
    long  last_active;

    int length;
    unsigned char buffer[MAX_BUFFLEN];
    int (*callback)(int fd, int event, void *arg);
}ev_node;

typedef struct event_block{
    ev_node * en_arry;
    struct event_block *next;
}ev_block;

typedef struct _Reactor{
    int epfd;            // epoll 文件描述符
    int flage;
    ev_block* evblock;
}reactor;

2.完成代码

代码如下(示例):

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>

#define EPOLL_OK    1
#define EPOLL_FAIL -1
#define MAX_BUFFLEN 1024
#define MAX_SIZE    1024   
typedef int (*Callback)(int, int, void*);
/*event结构体*/
typedef struct event_node{
    int fd;
    int events;
    int status;
    void* arg;
    long  last_active;

    int length;
    unsigned char buffer[MAX_BUFFLEN];
    int (*callback)(int fd, int event, void *arg);
}ev_node;

typedef struct event_block{
    ev_node * en_arry;
    struct event_block *next;
}ev_block;

typedef struct _Reactor{
    int epfd;            // epoll 文件描述符
    int flage;
    ev_block* evblock;
}reactor;
int sendOpr(int fd, int events, void*arg);
int recvOpr(int fd, int events, void*arg);
int acceptOpr(int fd, int events, void*arg);

int evblock_alloc(reactor* evloop)
{
    if(NULL == evloop || NULL == evloop->evblock){
        return EPOLL_FAIL;
    }
    ev_block *tailblockt = (ev_block*)malloc(sizeof(ev_block));
    while(tailblockt->next != NULL){
        tailblockt = tailblockt->next;
    }

    ev_block *blockt = (ev_block*)malloc(sizeof(ev_block));
    memset(blockt, 0, sizeof(blockt));

    ev_node* arry = (ev_node*)malloc(MAX_BUFFLEN*sizeof(ev_node));
    if(arry  == NULL){
        return  EPOLL_FAIL;
    }
    
    blockt->en_arry = arry;
    blockt->next = NULL;

    tailblockt->next = blockt;
    evloop->evblock++;
    return EPOLL_OK;
}
/*reactor 查找下个节点*/
ev_node *evblock_index(reactor* evloop, int ser_fd)
{
    int i,index;
    index = ser_fd / MAX_SIZE;
    while(index>=evloop->evblock){
        evblock_alloc(evloop);
    }
    ev_block *index_block = evloop->evblock;
    while((i++<index)&&(NULL!=index_block) ){
        index_block = index_block->next;
    }
    return  &index_block->en_arry[ser_fd%MAX_SIZE];
} 
/*event 事件初始化*/
int event_init(ev_node *node, int ser_fd,Callback callback,void* arg)
{
    if(NULL == node){
        return EPOLL_FAIL;
    }
    node->events = 0;
    node->fd = ser_fd;
    node->arg = arg;
    node->callback = callback;
    node->last_active = time(NULL);
    return EPOLL_OK;
}
/*event 事件添加*/
int event_add(int epfd, int events, ev_node *node)
{
    struct epoll_event ep = {0, {0}};
    ep.events = node->events = events;
    ep.data.ptr = node;

    if(node->status == 1){
        //修改ep
        if(epoll_ctl(epfd, EPOLL_CTL_MOD,node->fd, &ep)< 0){
            perror("EPOLL_CTL_MOD:");
            return EPOLL_FAIL;
        }
    }else if(node->status == 0){
        //添加ep
        if(epoll_ctl(epfd, EPOLL_CTL_ADD,node->fd, &ep)< 0){
            perror("EPOLL_CTL_ADD:");
            return EPOLL_FAIL;
        }
        node->status = 1;
    }

    return EPOLL_OK;
}
/*event 事件删除*/
int event_del(int epfd, ev_node* node)
{
    struct epoll_event ep = {0, {0}};
    if(node->status != 1) return EPOLL_FAIL;
    node->status  =0;
    ep.data.ptr = node;
    if(epoll_ctl(epfd, EPOLL_CTL_DEL, node->fd, &ep)){
        printf("epoll_ctl is error!\n");
        return EPOLL_FAIL; 
    }
    return EPOLL_OK;
}
/*reactor 初始化*/
int reactor_init(reactor* evloop)
{
    //初始化evloop反应堆
    memset(evloop, 0, sizeof(reactor));
    evloop->epfd = epoll_create(1);
    
    //初始化evblock连接器
    ev_block *block = (ev_block*)malloc(sizeof(ev_block));
    if(NULL == block){
        close(evloop->epfd);
        return EPOLL_FAIL;
    }
    memset(block, 0, sizeof(block));
    
    //初始阿虎ev_node节点
    ev_node*node = (ev_node*)malloc(MAX_SIZE*sizeof(ev_node)); 
    if(NULL == node){
        close(evloop->epfd);
        return EPOLL_FAIL;
    }
    memset(node, 0, sizeof(node));

    //将evloop、block和node建立关联
    block->en_arry =node;
    block->next = NULL; 

    evloop->flage = 1;
    evloop->evblock = block;
    return EPOLL_OK;
}
/*reactor 注册*/
int reactor_addlist(reactor* evloop, int ser_fd, Callback accept_cb)
{
    if(NULL == evloop || NULL == evloop->evblock){
        return EPOLL_FAIL;
    }
    int ret = 0;
    ev_node *node = evblock_index(evloop, ser_fd);
    ret=event_init(node, ser_fd, acceptOpr, evloop);
    if(ret < 0){
        printf("event_init is error!\n");
        return EPOLL_FAIL;
    }
    ret=event_add(evloop->epfd, EPOLLIN, node);
    if(ret < 0){
        printf("event_add is error!\n");
        return EPOLL_FAIL;
    }
    return EPOLL_OK;
}
/*reactor 运行*/
int reactor_run(reactor* evloop)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
{
    int connect_id, i;
    struct epoll_event events[MAX_SIZE + 1];
    for(;;)
    {
        connect_id = epoll_wait(evloop->epfd, events, MAX_SIZE, 1000);
        if(connect_id < 0){
            continue;
        }
        for(i=0; i< connect_id; ++i)
        { 
            ev_node* node= (ev_node*)events[i].data.ptr;
            if((events[i].events & EPOLLIN) && (node->events & EPOLLIN) ){
                node->callback(node->fd, events[i].events, node->arg);
            }
            if((events[i].events & EPOLLOUT) && (node->events & EPOLLOUT)){
                node->callback(node->fd, events[i].events, node->arg);
            }

        }
    }
    return EPOLL_OK;
}
/*reactor 卸载*/
int reactor_destory(reactor* evloop)
{
    close(evloop->epfd);
    free(evloop->evblock);
    evloop = NULL;
    return EPOLL_OK;
}

int acceptOpr(int fd, int events, void*arg)
{
    reactor* ev = (reactor*)arg;
    if(NULL == ev){return EPOLL_FAIL;}
    struct sockaddr_in clientadd;
    socklen_t clen = sizeof(clientadd);
    int clifd; 
    if((clifd = accept(fd, (struct sockaddr*)&clientadd, &clen)) ==-1){
        if(errno!=EAGAIN && errno != EINTR)
        perror("accept error!\n");
        return EPOLL_FAIL; 
    }
    ev_node* node = evblock_index(ev,clifd);
    event_init(node,clifd,recvOpr,ev);
    event_add(ev->epfd,EPOLLIN,node);
    return EPOLL_OK;

}
int recvOpr(int fd, int events, void*arg)
{
    reactor*evloop = (reactor*)arg;
    ev_node *ev = evblock_index(evloop, fd);
    int len = recv(fd, ev->buffer, MAX_BUFFLEN, 0);
    event_del(evloop->epfd, ev);
    if(len > 0){
        printf("%s\n", ev->buffer);
        event_del(evloop->epfd, ev);
        event_init(ev, fd, sendOpr, evloop);
        event_add(evloop->epfd, EPOLLOUT, ev);
    }else if(len ==0){
        event_del(evloop->epfd, ev);
        close(fd);
        printf("No recv...\n");
    }else{
        event_del(evloop->epfd, ev);
        printf("client[%d],reacv error\n", fd);
        close(fd);
    }
    return EPOLL_OK;
}
int sendOpr(int fd, int events, void*arg)
{
    reactor *evloop = (reactor*)arg;
    ev_node *ev = evblock_index(evloop, fd);
    
    int ret = send(fd, ev->buffer, ev->length, 0);
    if(ret<0){
        event_del(evloop->epfd, ev);
        close(fd);
    }else if(ret ==0){
        event_del(evloop->epfd, ev);
        close(fd);
    }else{
        printf("send to client[%d]:%s\n", fd, ev->buffer);
        event_del(evloop->epfd, ev);
        event_init(ev, fd, recvOpr, evloop);
        event_add(evloop->epfd, EPOLLIN, ev);
    }
    return EPOLL_OK;
}

/*socket初始化*/
int socket_init(unsigned short port)
{
    int ser_fd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in my_addr;
    memset(&my_addr, 0,sizeof(my_addr));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port   = htons(port);
    my_addr.sin_addr.s_addr= htonl(INADDR_ANY);
    
    bind(ser_fd, (struct sockaddr*)&my_addr, (socklen_t)sizeof(my_addr));
    listen(ser_fd, 10);
    return ser_fd;
}

int main(int argc, char* argv[])
{
    unsigned short port = atoi(argv[1]);
    int ser_fd = socket_init(port);
    int ret = 0;
    reactor* evloop = (reactor*)malloc(sizeof(reactor));
    ret = reactor_init(evloop);
    if(ret < 0){
        printf("reactor_init...\n");
        return 0;
    }
    reactor_addlist(evloop, ser_fd, acceptOpr);
    reactor_run(evloop);
    reactor_destory(evloop);
    close(ser_fd);
}


总结

以上为Reactor模型的简单归纳和总结,以便于以后方便回顾和熟悉,在文章中参考了大量网上优秀文章的内容。
https://zhuanlan.zhihu.com/p/93612337#
https://cloud.tencent.com/developer/article/1811347

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值