2022-07-29 epoll与reactor模型

/*
 * @Author: huichangren [email protected]
 * @Date: 2022-07-28 22:14:36
 * @LastEditors: huichangren [email protected]
 * @LastEditTime: 2022-07-29 00:16:40
 * @FilePath: /epoll_reactor/main.cpp
 * @Description: epoll 与reactor模型
 */
#include 
#include  
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
static const int MAX_EVENTS = 1024;     //最大事件数
static const int BUFFER_LEN = 128;      //缓存大小
static const int SERVER_PORT = 8080;           //服务端口

void RecvData(int fd, int events, void *arg);       //读数据回调
void SendData(int fd, int events, void *arg);       //发数据回调


/*
 * m_status:1表示在监听事件中,0表示不在 
 * last_active:记录最后一次响应时间,做超时处理
 */
struct MyEvent
{
    typedef  void (*EventCallBack)(int ,int , void *) ;
    int m_fd;                                           //文件描述符
    int m_events;                                   //事件类型:EPOLLIN|EPOLLOUT
    void *m_args;                                   //回调参数
    EventCallBack m_callback;             //事件回调
    int m_status;
    char m_buf[BUFFER_LEN];          //缓存
    int m_buff_len;                               /缓存中数据的大小
    long m_last_active;                       //上次激活的时间戳
};

struct MyEvent myevents[MAX_EVENTS+1];         //事件集合
int global_epoll_fd;                    //epoll_create返回的句柄

//设置事件接口
void SetEvent(MyEvent *event,int fd,void (*call_back)(int ,int , void *),void *arg)
{
    event->m_fd = fd;
    event->m_callback = call_back;
    event->m_events = 0;
    event->m_args = arg;
    event->m_status = 0;
    memset(event->m_buf,0,sizeof(event->m_buf));
    event->m_buff_len = 0;
}
//添加事件
void AddEvent(int epoll_fd,int events,MyEvent *event)
{
   struct epoll_event ep_event;
    memset(&ep_event,0,sizeof(ep_event));
    int option =0;
    ep_event.data.ptr = event;       //让epoll事件指向自定义事件
    ep_event.events = event->m_events = events;  //给事件赋值
    if (event->m_status == 1)
    {
        option = EPOLL_CTL_MOD;             //改变epoll中的事件
    }else
    {
        option  = EPOLL_CTL_ADD;
        event->m_status = 1;
    }
     if (epoll_ctl(epoll_fd, option, event->m_fd, &ep_event) < 0)
     {
        printf("event add failed [fd=%d], events[%d]\n", event->m_fd, events);
     }
    else
    {
        printf("event add OK [fd=%d], op=%d, events[%0X]\n", event->m_fd, option, events);
    }
}

//删除事件
void DelEvent(int epoll_fd, MyEvent *event)
{
    struct epoll_event ep_event;
    memset(&ep_event,0,sizeof(ep_event));
    if (event->m_status != 1)
        return;

    ep_event.data.ptr = event;
    event->m_status = 0;
    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, event->m_fd, &ep_event);
}

//接受链接接口
void AcceptConn(int listen_fd, int events, void*args)
{
    struct sockaddr_in cin;
    socklen_t len = sizeof(cin);      //对端地址
    int conn_fd;                    //链接fd
    if((conn_fd= accept(listen_fd,(struct sockaddr*)&cin,&len))==-1)
    {
        if (errno != EAGAIN && errno != EINTR) {
            fprintf(stderr,"errno EAGAIN && EINTR signal happen");
            return;
        }
        fprintf(stderr,"accept failed!");
        return;
    }
    int i = 0;
    do
    {
        for ( i = 0; i < MAX_EVENTS; i++)   //找到事件集合中事件是空的事件的index i
        {
            if (myevents[i].m_status==0)
            {
                break;
            }
        }
        if (i == MAX_EVENTS)//超出链接数
        {
            printf("%s: max connect limit[%d]\n", __func__, MAX_EVENTS);
            break;
        }
        int ret = 0;
        if ((ret = fcntl(conn_fd,F_SETFL,O_NONBLOCK))<0)
        {//设置非阻塞
            printf("%s: set nonblocking failed, %s\n", __func__, strerror(errno));
            break;
        }
        
        SetEvent(&myevents[i], conn_fd, RecvData, &myevents[i]);    //添加事件到事件集合
        AddEvent(global_epoll_fd, EPOLLIN, &myevents[i]);           //添加读事件触发
    
    } while (0);
    printf("new connect [%s:%d][time:%ld], pos[%d]\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), myevents[i].m_last_active, i);
    
    return;
}

void RecvData(int fd,int events,void *arg)
{
    struct MyEvent *event = (struct MyEvent *)arg;
    int len = recv(fd, event->m_buf, sizeof(event->m_buf), 0); //从fd中读取数据到event中buf
    DelEvent(global_epoll_fd, event);                           //数据读完了,就把从事件集合中删除

    if (len > 0) {
        event->m_buff_len = len;
        event->m_buf[len] = '\0';
        printf("C[%d]:%s\n", fd, event->m_buf);
        /* 转换为发送事件 */
        SetEvent(event, fd, SendData, event);
        AddEvent(global_epoll_fd, EPOLLOUT, event);
    }
    else if (len == 0) {
        close(event->m_fd);
    }
    else {
        close(event->m_fd);
        printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
    }
}

void SendData(int fd, int events, void *arg)
{
    struct MyEvent *ev = (struct MyEvent *)arg;
    int len = send(fd, ev->m_buf, ev->m_buff_len, 0);   


    DelEvent(global_epoll_fd, ev);
    if (len > 0) {
        printf("send[fd=%d], [%d]%s\n", fd, len, ev->m_buf);
        SetEvent(ev, fd, RecvData, ev);
        AddEvent(events, EPOLLIN, ev);
    }
    else {
        close(ev->m_fd);
        printf("send[fd=%d] error %s\n", fd, strerror(errno));
    }
}
void InitListenSocket(int efd, short port)
{
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    fcntl(listen_fd, F_SETFL, O_NONBLOCK);
    SetEvent(&myevents[MAX_EVENTS], listen_fd, AcceptConn, &myevents[MAX_EVENTS]);//添加处理链接的事件
    AddEvent(efd, EPOLLIN, &myevents[MAX_EVENTS]);

    struct sockaddr_in sin;

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(port);

    int ret = bind(listen_fd, (struct sockaddr *)&sin, sizeof(sin));
    if (ret < 0)
    {
        fprintf(stderr,"bind error");
        return;
    }
    

    ret =  listen(listen_fd, 10);
    if (ret < 0)
    {
        fprintf(stderr,"listen failed");
        return;
    }
}
int main(int argc, char *argv[])
{
    unsigned short port = SERVER_PORT;

    if (argc == 2)
        port = atoi(argv[1]);

    global_epoll_fd = epoll_create(MAX_EVENTS+1);

    if (global_epoll_fd <= 0)
        printf("create efd in %s err %s\n", __func__, strerror(errno));

    InitListenSocket(global_epoll_fd, port);

    /* 事件循环 */
    struct epoll_event events[MAX_EVENTS+1];

    printf("server running:port[%d]\n", port);
    int checkpos = 0, i;
    while (1) {
        long now = time(NULL);
        for (i = 0; i < 100; i++, checkpos++) {
            if (checkpos == MAX_EVENTS)
                checkpos = 0;
            if (myevents[checkpos].m_status != 1)
                continue;
            long duration = now - myevents[checkpos].m_last_active;
            if (duration >= 60) {
                close(myevents[checkpos].m_fd);
                printf("[fd=%d] timeout\n", myevents[checkpos].m_fd);
                DelEvent(global_epoll_fd, &myevents[checkpos]);
            }
        }
        /* 等待事件发生 */
        int nfd = epoll_wait(global_epoll_fd, events, MAX_EVENTS+1, 1000);
        if (nfd < 0) {
            printf("epoll_wait error, exit\n");
            break;
        }
        for (i = 0; i < nfd; i++) {
            struct MyEvent *ev = (struct MyEvent *)events[i].data.ptr; //拿到ptr指向的自定义事件
            if ((events[i].events & EPOLLIN) && (ev->m_events & EPOLLIN)) {
                ev->m_callback(ev->m_fd, events[i].events, ev->m_args);         //执行里面的回调
            }
            if ((events[i].events & EPOLLOUT) && (ev->m_events & EPOLLOUT)) {
                ev->m_callback(ev->m_fd, events[i].events, ev->m_args);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(2022-07-29 epoll与reactor模型)