记录 Reactor模型的基本实现 单线程

介绍

Linux环境使用epoll实现基本的Reactor单线程模型,主要用来记录代码思路并实现基本功能,不做复杂逻辑。

Reactor头文件

#ifndef REACTOR_H
#define REACTOR_H

#include <stdio.h>
#include <unistd.h> // read write
#include <fcntl.h> // fcntl
#include <sys/types.h> // listen
#include <sys/socket.h> // socket
#include <errno.h> // errno
#include <arpa/inet.h> // inet_addr htons
#include <sys/epoll.h>
#include <stdlib.h> // malloc
#include <string.h> // memcpy memmove

#define MAX_EVENT_NUM 512
#define MAX_CONN ((1<<16)-1)
#define MSG_SIZE 1024

//事件回调
typedef void (*event_cb)(int fd, int eventType, void *privdata);
typedef void (*error_cb)(int fd, char *err);

struct Reactor
{
    
    
    int epfd;
    int listenfd;
    int stop;
    struct epoll_event events[MAX_EVENT_NUM];
};

struct CustomEvent
{
    
    
    int fd;
    Reactor *reactor;
    char recv[MSG_SIZE];
    char send[MSG_SIZE];
    event_cb readCb;
    event_cb writeCb;
    error_cb errorCb;
};

//callback func
void read_cb(int fd, int eventType, void *privdata);
void accept_cb(int fd, int eventType, void *privdata);

//func
int set_nonblock(int fd);

Reactor *create_reactor();
void release_reactor(Reactor *r);
void eventloop_once(Reactor *r, int timeout);
void start_eventloop(Reactor *r);
void stop_eventloop(Reactor *r);

CustomEvent *new_event(Reactor *r, int fd, event_cb readcb, event_cb writecb, error_cb errcb);
void free_event(CustomEvent *e);
int add_event(Reactor *r, int eventType, CustomEvent *e);
int del_event(Reactor *r, CustomEvent *e);

int create_server(Reactor *r, short port, event_cb accept);

#endif // REACTOR_H

Reactor实现文件

#include "reactor.h"

void read_cb(int fd, int eventType, void *privdata)
{
    
    
    CustomEvent *e = (CustomEvent *)privdata;
    int n = read(fd, e->recv, MSG_SIZE);
    if (n == 0)
    {
    
    
        printf("close connection fd = %d\n", fd);
        del_event(e->reactor, e);
        close(fd);
        return;
    }
    else if (n < 0)
    {
    
    
        printf("read error fd = %d err = %s\n", fd, strerror(errno));
        if (e->errorCb)
            e->errorCb(fd, strerror(errno));

        del_event(e->reactor, e);
        close(fd);
        return;
    }
    else
    {
    
    
        printf("recv data from client:%s\n", e->recv);
        memset(e->recv, 0, MSG_SIZE);

        //回写
        char msg[] = "replay info";
        write(e->fd, msg, sizeof(msg));
    }
}

void accept_cb(int fd, int eventType, void *privdata)
{
    
    
    CustomEvent *e = (CustomEvent *)privdata;

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(struct sockaddr_in));
    socklen_t len = sizeof(addr);

    int clientfd = accept(fd, (struct sockaddr*)&addr, &len);
    if (clientfd <= 0)
    {
    
    
        printf("accept failed\n");
        return;
    }

    char str[INET_ADDRSTRLEN] = {
    
    0};
    printf("recv from %s at port %d\n", inet_ntop(AF_INET, &addr.sin_addr, str, sizeof(str)), ntohs(addr.sin_port));

    CustomEvent *ce = new_event(e->reactor, clientfd, read_cb, 0, 0);
    add_event(ce->reactor, EPOLLIN, ce);
    set_nonblock(clientfd);
}


int set_nonblock(int fd)
{
    
    
    int flag = fcntl(fd, F_GETFL, 0);
    return fcntl(fd, F_SETFL, flag | O_NONBLOCK);
}

Reactor *create_reactor()
{
    
    
    Reactor *r = (Reactor *)malloc(sizeof(Reactor));
    r->epfd = epoll_create(1);
    r->listenfd = 0;
    r->stop = 0;
    memset(r->events, 0, sizeof(struct epoll_event) * MAX_EVENT_NUM);
    return r;
}

void release_reactor(Reactor *r)
{
    
    
    stop_eventloop(r);
    close(r->epfd);
    free(r);
}

void eventloop_once(Reactor *r, int timeout)
{
    
    
    int n = epoll_wait(r->epfd, r->events, MAX_EVENT_NUM, timeout);
    for (int i = 0; i < n; i++)
    {
    
    
        struct epoll_event *e = &r->events[i];
        int mask = e->events;
        if (e->events & EPOLLERR)
            mask |= EPOLLIN | EPOLLOUT;
        if (e->events & EPOLLHUP)
            mask |= EPOLLIN | EPOLLOUT;

        CustomEvent *ce = (CustomEvent*)e->data.ptr;
        if (mask & EPOLLIN)
        {
    
    
            if (ce->readCb)
                ce->readCb(ce->fd, EPOLLIN, ce);
        }
        if (mask & EPOLLOUT)
        {
    
    
            if (ce->writeCb)
            {
    
    
                ce->writeCb(ce->fd, EPOLLOUT, ce);
            }
            else
            {
    
    
                //write buf
            }
        }
    }
}

void start_eventloop(Reactor *r)
{
    
    
    while (!r->stop)
    {
    
    
        eventloop_once(r, -1);
    }
}

void stop_eventloop(Reactor *r)
{
    
    
    r->stop = 1;
}

CustomEvent *new_event(Reactor *r, int fd, event_cb readcb, event_cb writecb, error_cb errcb)
{
    
    
    CustomEvent *e = (CustomEvent *)malloc(sizeof(CustomEvent));
    e->reactor = r;
    e->fd = fd;
    memset(e->recv, 0, MSG_SIZE);
    memset(e->send, 0, MSG_SIZE);
    e->readCb = readcb;
    e->writeCb = writecb;
    e->errorCb = errcb;
    return e;
}

void free_event(CustomEvent *e)
{
    
    
    free(e);
}

int del_event(Reactor *r, CustomEvent *e)
{
    
    
    epoll_ctl(r->epfd, EPOLL_CTL_DEL, e->fd, NULL);
    free_event(e);
    return 0;
}

int add_event(Reactor *r, int eventType, CustomEvent *e)
{
    
    
    struct epoll_event ev;
    ev.events = eventType;
    ev.data.ptr = e;

    if (epoll_ctl(r->epfd, EPOLL_CTL_ADD, e->fd, &ev) == -1)
    {
    
    
        printf("add event err fd = %d\n", e->fd);
        return 1;
    }

    return 0;
}

int create_server(Reactor *r, short port, event_cb accept)
{
    
    
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd < 0)
    {
    
    
        printf("create listenfd error!\n");
        return -1;
    }

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

    int reuse = 1;
    if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(int)) == -1)
    {
    
    
        printf("reuse address error: %s\n", strerror(errno));
        return -1;
    }

    if (bind(listenfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0)
    {
    
    
        printf("bind error %s\n", strerror(errno));
        return -1;
    }

    if (listen(listenfd, 5) < 0)
    {
    
    
        printf("listen error %s\n", strerror(errno));
        return -1;
    }

    if (set_nonblock(listenfd) < 0)
    {
    
    
        printf("set_nonblock error %s\n", strerror(errno));
        return -1;
    }

    r->listenfd = listenfd;

    CustomEvent *e = new_event(r, listenfd, accept, 0, 0);
    add_event(r, EPOLLIN, e);

    printf("listen port : %d\n", port);
    return 0;
}

调用

#include <iostream>
#include "reactor.h"

using namespace std;

int main()
{
    
    
    Reactor *reactor = create_reactor();
    if (create_server(reactor, 8989, accept_cb) < 0)
    {
    
    
        release_reactor(reactor);
        return 1;
    }

    start_eventloop(reactor);
    release_reactor(reactor);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/T__zxt/article/details/128371775
今日推荐