• 高性能的事件并发框架的实现


    引言:lighttpd与nginx这些新兴的webserver框架都以支撑大规模的并发而闻名,以下介绍一个我自己实现的并使用的并发事件框架,这个框架不止包括网络事件,也包括其他耗时事件比如IO等都可以在事件框架中运行。


    1,监听事件的初始化。
    以下是一个事件结构的大致成员,我们以Epoll模型为例子,包括描述符的数组,和事件的回调函数。
    初始化要分配以最大值为限制的fdnode的数组。
    typedef struct fdevents {
    struct server *srv;
    fdevent_handler_t type;
    fdnode **fdarray;
    size_t maxfds;
    #ifdef EPLOLL
    int epoll_fd;
    struct epoll_event *epoll_events;
    #endif
    int (*reset)(struct fdevents *ev);
    void (*free)(struct fdevents *ev);
    int (*event_set)(struct fdevents *ev, int fde_ndx, int fd, int events);
    int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
    int (*event_get_revent)(struct fdevents *ev, size_t ndx);
    int (*event_get_fd)(struct fdevents *ev, size_t ndx);
    int (*event_next_fdndx)(struct fdevents *ev, int ndx);
    int (*poll)(struct fdevents *ev, int timeout_ms);
    int (*fcntl_set)(struct fdevents *ev, int fd);
    } fdevents;
    2,事件的注册
    int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) 
    将事件新增进数组fdarray中,这样在事件满足时,就会再相应的条件触发回调函数handler,
    这个注册会初始化一个fdnode 
    3,事件的设置
    int fdevent_event_set(fdevents *ev, int *fde_ndx, int fd, int events) 
    将对应的fdnode 指定为那种IO事件的响应,IO事件有如下种类
    #define FDEVENT_IN     BV(0)
    #define FDEVENT_PRI    BV(1)
    #define FDEVENT_OUT    BV(2)
    #define FDEVENT_ERR    BV(3)
    #define FDEVENT_HUP    BV(4)
    #define FDEVENT_NVAL   BV(5)
     
    4,事件Poll动作,将所有触发的事件返回到fdndx的链表上,处理逻辑可以对相应的事件做逻辑处理
    int fdevent_poll(fdevents *ev, int timeout_ms)
     
    5,fd的回调函数
    typedef handler_t (*fdevent_handler)(struct server *srv, void *ctx, int revents);
    当有事件发生是,所有逻辑都包括在回调函数中,以下代码是poll后的典型处理
    do {
    fdevent_handler handler;
    void *context;
    handler_t r;
    fd_ndx  = fdevent_event_next_fdndx (srv->ev, fd_ndx);
    if (-1 == fd_ndx) break; 
                                    //这里的3种回调函数是事件模型对应的真实实现,比如epoll的实现
                                    //则对应的是epoll实现代码中的
                                    //fdevent_event_get_revent获取对应事件
                                    //fdevent_event_get_fd 获取文件描述符
                                    // fdevent_get_handler 获取事件回调函数
                                    //  fdevent_get_context 获取事件逻辑数据
    revents = fdevent_event_get_revent (srv->ev, fd_ndx);
    fd      = fdevent_event_get_fd     (srv->ev, fd_ndx);
    handler = fdevent_get_handler(srv->ev, fd);
    context = fdevent_get_context(srv->ev, fd);
     
    switch (r = (*handler)(srv, context, revents)) {
    case HANDLER_FINISHED:                    //针对处理的返回值做不同的处理
    case HANDLER_GO_ON:                        
    case HANDLER_WAIT_FOR_EVENT:
    case HANDLER_WAIT_FOR_FD:
    break;
    case HANDLER_ERROR:
    SEGFAULT();
    break;
    default:
    log_error_write(srv, __FILE__, __LINE__, "d", r);
    break;
    }
    } while (--n > 0);
     
    5,事件框架,多路复用模型(epoll,select,kquque,FIFO等),具体的数据逻辑相互分离
     
     
    6,网络事件注册进事件框架(建立连接)
    网络事件也作为普通事件之一注册进事件框架
    fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
    fdevent_event_set(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
     
    network_server_handle_fdevent 实际上做了accpet的实现,当网络事件被Poll函数触发是,由network_server_handle_fdevent 来执行建立连接的动作。
    7,网络事件注册进事件框架(读写事件)
    在network_server_handle_fdevent 中注册读写事件,针对读写来实现对于的操作在connection_handle_fdevent实现
    fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
     
    8,读写事件的逻辑抽象化实现
    业务逻辑跟进自己逻辑需要独立开来,对于网络事件来说,只需要关心是否可读写就可以,为此每个连接都要维护一个缓冲区链表,将业务与网络进行隔离。
    typedef struct {
    chunk *first;
    chunk *last;
    chunk *unused;
    size_t unused_chunks;
    array *tempdirs;
    off_t  bytes_in, bytes_out;
    } chunkqueue;
  • 相关阅读:
    sstream && istringstream && ostringstream
    动态规划
    状态空间搜索(转)
    数学知多少
    挣得值分析法
    adobe acrobat pro 8.0/8.1 激活方法
    ZooKeeper Overview
    Java网络编程从入门到精通(25):创建ServerSocket对象
    使用 Spring 2.5 基于注解驱动的 Spring MVC(二)
    一起偶遇网随机视频测试版
  • 原文地址:https://www.cnblogs.com/konyel/p/3183195.html
Copyright © 2020-2023  润新知