epoll反应堆模型实现

#include <iostream>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <sys/epoll.h>
#include <memory>
#include <string.h>
#include <fcntl.h>

using namespace std;
using std::cin;
using std::cout;
using std::endl;
using std::string;

#define SERV_PORT       6666
#define BACKLOG         128
#define BUFLEN          1024
#define MAXUSER         1024

struct event_s {
    int fd;
    int events;
    void *arg;
    void (*call_back)(int fd, int events, void *arg);
    int status;
    char buf[BUFLEN];
    int len;
    long last_active;
};

void RecvData(int fd, int events, void *arg);
void SendData(int fd, int events, void *arg);
void SysError(const char * msg);
void InitListenSocket(int efd, unsigned short serv_port);
void EventSet(event_s *events, int fd, void (*fun)(int, int, void *), void *arg);
void EventAdd(int efd, int events, event_s *evt);
void EventDel(int efd, event_s *evt);
void AcceptConn(int lfd, int events, void *arg);

int g_efd;         //global root
struct event_s g_events[MAXUSER + 1]; //all user and listen fd

int main(int argc, char *argv[]) {
    unsigned short serv_port = SERV_PORT;
    if(argc == 2) {
        serv_port = atoi(argv[1]);
    }
    g_efd = epoll_create(MAXUSER);
    InitListenSocket(g_efd, serv_port);
    struct epoll_event wait_events[MAXUSER + 1];
    bzero(&wait_events, sizeof(wait_events));
    puts("server running.");
    int checkpos = 0, i;
    while(1) {
        long now = time(nullptr);
        for(int i = 0; i < 100; i++, checkpos++) {
            if(checkpos == MAXUSER) checkpos = 0;
            if(g_events[checkpos].status == 0) continue;
            long duration = now - g_events[checkpos].last_active;
            if(duration >= 60) {
#if DEBUG 
                printf("duration = %ld\n", duration);
#endif
                close(g_events[checkpos].fd);
                printf("[fd=%d] timeout\n", g_events[checkpos].fd);
                EventDel(g_efd, &g_events[checkpos]);
            }
        }
        int nfd = epoll_wait(g_efd, wait_events, MAXUSER + 1, 1000);
        if(nfd < 0) {
            SysError("epoll_wait error.");
        }
#if DEBUG
        printf("nfd = %d\n", nfd);
#endif
        for(int i = 0; i < nfd; i++) {
            struct event_s *ev = (event_s *)wait_events[i].data.ptr;
            if((wait_events[i].events & EPOLLIN) && (ev->events & EPOLLIN)) {
#if DEBUG
                puts("EPOLLIN");
#endif 
                ev->call_back(ev->fd, wait_events[i].events, ev->arg);
            }
            if((wait_events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)) {
                ev->call_back(ev->fd, wait_events[i].events, ev->arg);
            }
        }
    }

    return 0;
}

void SysError(const char * msg) {
    perror(msg);
    exit(1);
}

void InitListenSocket(int efd, unsigned short serv_port) {
    for(int i = 0; i < MAXUSER + 1; i++) {
        g_events[i].fd = 0;
    }
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1) { 
        string errMsg = (string)__func__ + " failed.";
        SysError(errMsg.c_str());
    }
    fcntl(lfd, F_SETFL, O_NONBLOCK);
    int opt = 1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    EventSet(&g_events[MAXUSER], lfd, AcceptConn, (void *)&g_events[MAXUSER]);
    EventAdd(g_efd, EPOLLIN, &g_events[MAXUSER]);
    sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family          = AF_INET;
    serv_addr.sin_port            = htons(serv_port);
    serv_addr.sin_addr.s_addr     = htonl(INADDR_ANY);
    
    if(bind(lfd, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        register const string errMsg = (string)__func__ + ": bind error."; 
        SysError(errMsg.c_str());
    }
    
    register int lis = listen(lfd, BACKLOG);
    if(lis == -1) {
        SysError("InitListenSocket listen failed.");
    }
    puts("Listen Success...");
}

void RecvData(int fd, int events, void *arg) {
    struct event_s *ev = (struct event_s *)arg;
    int len = recv(fd, ev->buf, sizeof(ev->buf), 0);
#if DEBUG 
    printf("%s: len=%d\n", __func__, len);
#endif
    EventDel(g_efd, ev);
    if(len > 0) {
        ev->len = len;
        ev->buf[len]='\0';
        printf("C: [%d]%s\n", ev->len - 1, ev->buf);

        EventSet(ev, fd, SendData, (void *)ev);
        EventAdd(g_efd, EPOLLOUT, (event_s *)ev->arg);
    } else if(len == 0) {
        close(ev->fd);
        printf("[fd=%d] has offline.", ev->fd);
    } else {
        SysError("RecvData error.");
    }
    return;
}
void SendData(int fd, int events, void *arg) {
    struct event_s *ev = (struct event_s *)arg;
#if DEBUG 
    printf("SendData buf = %s\n", ev->buf);
#endif
    int len = send(ev->fd, ev->buf, ev->len, 0);
    if(len > 0) {
        printf("send[fd=%d], [%d]%s\n", fd, len - 1, ev->buf);
        EventDel(g_efd, ev);
        EventSet(ev, fd, RecvData, (void *)ev);
        EventAdd(g_efd, EPOLLIN, ev);
    } else {
        close(ev->fd);
        EventDel(ev->fd, ev);
        printf("send[fd=%d] error: %s\n", fd, strerror(errno));
    }
    return;
}
void EventSet(event_s *events, int fd, void (*fun)(int, int, void *), void *arg) {
    events->fd          = fd;
    events->arg         = arg;
    events->events      = 0;
    events->status      = 0;
    events->call_back   = fun;
    events->last_active = time(NULL);
    return ;
}
void EventAdd(int efd, int events, event_s *evt) {
    epoll_event epv = {0, {0}};
    epv.events = evt->events = events;
    epv.data.ptr = (void *)evt;
    int op = EPOLL_CTL_ADD;
    if(evt->status == 1) {
        op = EPOLL_CTL_MOD;
    } else {
        evt->status = 1;
    }

    if(epoll_ctl(g_efd, op, evt->fd, &epv) < 0) {
        printf("event add [fd=%d] failed.\n", evt->fd);
    } else {
        printf("event add [fd=%d] OK.\n", evt->fd);
    }
    return ;
}
void EventDel(int efd, event_s *evt) {
    epoll_event epv = {0, {0}};
    if(evt->status != 1) return;
    epv.data.ptr = evt;
    evt->status = 0;
    epoll_ctl(g_efd, EPOLL_CTL_DEL, evt->fd, &epv);
}
void AcceptConn(int lfd, int events, void *arg) {
#if DEBUG
    puts("AcceptConn");
#endif
    sockaddr_in client_addr;
    memset(&client_addr, 0, sizeof(client_addr));
    socklen_t len = sizeof(client_addr);
    int cfd = accept(lfd, (sockaddr *)&client_addr, &len);
    if(cfd < 0) {
        SysError("AcceptConn accept error."); 
    }
    int pos = 0;
    for(pos = 0; pos < MAXUSER; pos++) {
        if(g_events[pos].fd == 0) {
            break;
        }
    }
    if(pos == MAXUSER) {
        puts("User Online is Max.");
        close(cfd);
        return;
    }
#if DEBUG 
    printf("AcceptConn: cfd = %d\n", cfd);
#endif
    fcntl(cfd, F_SETFL, O_NONBLOCK);
    EventSet(&g_events[pos], cfd, RecvData, (void *)&g_events[pos]);
    EventAdd(g_efd, EPOLLIN, &g_events[pos]);
    char IP[50];
    inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, IP, sizeof(IP));
    printf("[IP=%s] with [port=%d] has online.\n", IP, ntohs(client_addr.sin_port));
    return;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值