博客园  :: 首页  :: 新随笔  :: 管理

2.1.2 reactor的原理与百万并发

Posted on 2023-03-04 03:40  wsg_blog  阅读(75)  评论(0编辑  收藏  举报

Linux C/C++服务器

reactor的原理与百万并发

五元组

五元组:sip,sport,dip,dport,proto 源IP,源端口,目的IP,目的端口,协议
tcp的端口最大支持65536个,客户端和服务端ip都是固定的,为了测试百万并发,我们使用65536个客户端的端口,使用100个服务端的端口,也就是说服务端将会有100个listenfd在监听

reactor模型

reactor模型在epoll基础上新增动态扩容数组,使得每个fd都有自己的缓冲区buffer,并且查找fd也比较快

#define ITEM_LENGTH 1024
/*epoll 存在共用一个数据缓冲区问题,为了让每一个fd都有自己独立的缓冲区
所以就有了reactor*/
struct sock_item{   //conn_item
    int fd; //clientfd
    char *rbuffer;
    int rlength;
    char *wbuffer;
    int wlength;
    int event;
    //callback
    void (*recv_cb)(int fd, char *buffer, int length);
    void (*send_cb)(int fd, char *buffer, int length);
    void (*accept_cb)(int fd, char *buffer, int length);
};
 
/*动态扩容数组
1.在有序数据存储查找,动态扩容数组的空间和时间复杂度优于红黑树,并且结构简单,实际工作中经常会使用
*/
struct eventblock{
    struct sock_item *items;
    struct eventblock *next;
};

struct reactor{
    int epfd;
    int blkcnt;
    struct eventblock* evblk;
};

int reactor_resize(struct reactor *r){       //新增 eventblock 扩容
    if(r == NULL) return -1;
    struct eventblock *blk = r->evblk;
    while(blk != NULL && blk->next != NULL){   //移动到最后
        blk = blk->next;
    }
    struct sock_item *item = (struct sock_item*)malloc(ITEM_LENGTH * sizeof(struct sock_item));   //新增item数组
    if(item == NULL) return -4;
    memset(item, 0, ITEM_LENGTH * sizeof(struct sock_item));

    printf("---blkcnt---: %d\n", r->blkcnt);
    struct eventblock *block = (struct eventblock*)malloc(sizeof(eventblock));  //新增eventblock模块
    if(block == NULL){
        free(item);
        return -5;
    }
    memset(block, 0, sizeof(eventblock));

    block->items = item;    //新增eventblock赋值
    block->next = NULL;

    if(blk == NULL){
        r->evblk = block;      //连接eventblock模块
    } else {
        blk->next = block;
    }
    r->blkcnt++;
    
    return 0;
}

struct sock_item* reactor_lookup(struct reactor *r, int sockfd){
    if(r == NULL || sockfd <= 0) return NULL;

    int blkidx = sockfd / ITEM_LENGTH;

    //printf("reactor_lookup --> %d\n", r->blkcnt);
    while(blkidx >= r->blkcnt){     //超出边界
        reactor_resize(r);      //扩容
    }
    int i=0;
    struct eventblock *blk = r->evblk;
    while(i++ < blkidx && blk != NULL){
        blk = blk->next;
    }

    return &blk->items[sockfd % ITEM_LENGTH];
}

reactor百万并发代码