Skip to content

Instantly share code, notes, and snippets.

@baixiangcpp
Last active February 26, 2019 13:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baixiangcpp/be7872baa82d9b9c400b17a2b0fe5fe3 to your computer and use it in GitHub Desktop.
Save baixiangcpp/be7872baa82d9b9c400b17a2b0fe5fe3 to your computer and use it in GitHub Desktop.
A simple libevent-like reactor demo base on epoll api
/*
* @Author: baixiangcpp@gmail.com
* @Date: 2018-07-28 11:04:52
* @Last Modified by: baixiangcpp@gmail.com
* @Last Modified time: 2018-07-28 11:07:04
* @usage: An implementation of reactor design patterns base on epoll.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAX_EVENTS 100
#define BUF_SIZE 1024
void onError(const char *reason)
{
perror(reason);
exit(EXIT_FAILURE);
}
typedef void (*callback)(int fd, int events, void *arg);
struct event
{
int fd;
int events;
void *arg;
callback cb;
char *buf;
int bufsize;
struct event_base *base;
};
struct event_base
{
int epollfd;
};
struct event *event_new(struct event_base *base, int fd, int events, callback cb, void *arg)
{
struct event *ev = malloc(sizeof(struct event));
if (!ev)
return NULL;
ev->fd = fd;
ev->events = events;
ev->cb = cb;
ev->base = base;
ev->arg = arg;
ev->buf = malloc(BUF_SIZE);
ev->bufsize = BUF_SIZE;
bzero(ev->buf, BUF_SIZE);
return ev;
}
void event_add(struct event *ev)
{
struct epoll_event epollev;
epollev.events = ev->events;
epollev.data.ptr = ev;
if (epoll_ctl(ev->base->epollfd, EPOLL_CTL_ADD, ev->fd, &epollev) == -1)
onError("epoll_ctl add fd");
}
void event_del(struct event *ev)
{
if (epoll_ctl(ev->base->epollfd, EPOLL_CTL_DEL, ev->fd, NULL) == -1)
onError("epoll_ctl add fd");
close(ev->fd);
free(ev->buf);
free(ev);
}
void event_mod(struct event *ev, int events)
{
struct epoll_event epollev;
ev->events = events;
epollev.events = events;
epollev.data.ptr = ev;
if (epoll_ctl(ev->base->epollfd, EPOLL_CTL_MOD, ev->fd, &epollev) == -1)
onError("epoll_ctl add fd");
}
void recvdata(struct event *ev)
{
int ret = read(ev->fd, ev->buf, ev->bufsize);
if (ret <= 0) // error or peer close
{
event_del(ev);
return;
}
ev->buf[ret] = 0;
event_mod(ev, EPOLLOUT);
}
void senddata(struct event *ev)
{
int ret = write(ev->fd, ev->buf, strlen(ev->buf));
if (ret <= 0) // error or peer close
{
event_del(ev);
return;
}
event_mod(ev, EPOLLIN);
}
void handle_event(int fd, int events, void *arg)
{
struct event *ev = (struct event *)arg;
int ret = 0;
if (events == EPOLLIN)
recvdata(ev);
else if (events == EPOLLOUT)
senddata(ev);
}
void handle_conn(int fd, int events, void *arg)
{
struct event *ev = (struct event *)arg;
struct event_base *base = ev->base;
struct sockaddr_in addr = {0};
socklen_t addrlen = sizeof(addr); //value-result argument
char addrstr[20] = {0};
int socket = accept(fd, (struct sockaddr *)&addr, &addrlen);
if (socket == -1)
onError("accpet");
inet_ntop(AF_INET, &addr.sin_addr, addrstr, INET_ADDRSTRLEN);
printf("Accpet a new client,client addr is %s .\n", addrstr);
struct event *newev = event_new(base, socket, EPOLLIN, handle_event, NULL);
if (!newev)
onError("event_new");
event_add(newev);
}
int initServSocket(struct event_base *base, int port)
{
struct sockaddr_in sin;
int servsock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (servsock == -1)
onError("socket()");
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(port);
if (bind(servsock, (struct sockaddr *)&sin, sizeof(sin)) == -1)
onError("bind()");
listen(servsock, SOMAXCONN);
return servsock;
}
struct event_base *base_new()
{
struct event_base *base = malloc(sizeof(struct event_base));
if (!base)
onError("base_new");
int epollfd = epoll_create1(0);
if (epollfd == -1)
onError("epoll_create1");
base->epollfd = epollfd;
return base;
}
void base_dispatch(struct event_base *base)
{
int nfds;
struct epoll_event events[MAX_EVENTS];
for (;;)
{
int n = 0;
nfds = epoll_wait(base->epollfd, events, MAX_EVENTS, -1);
if (nfds == -1)
{
perror("epoll_wait");
exit(EXIT_FAILURE);
}
for (n = 0; n < nfds; ++n)
{
struct epoll_event epollev = events[n];
struct event *ev = (struct event *)epollev.data.ptr;
ev->cb(ev->fd, epollev.events, ev);
}
}
}
int main()
{
struct event_base *base = base_new();
int servsock = initServSocket(base, 8080);
struct event *ev = event_new(base, servsock, EPOLLIN, handle_conn, NULL);
if (!ev)
onError("event_new");
event_add(ev);
base_dispatch(base);
free(base);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment