Пример использования libevent2 для реализации TCP-сервера

libevent2 —  это библиотека предоставляющая механизм вызова callback-функций по приходу событий. Простой пример работы в виде TCP-сервера с буферизированным вводом/выводом. Небольшая напоминалочка себе.

 

Для начала инициализируем библиотеку. libevent2 инициализируется функцией event_init():

struct event_base *ev_base;
 
/* Инициализируем библиотеку */
event_init();
/* Указываем обработчик фатальный ошибок */
event_set_fatal_callback((event_fatal_cb) event_fatal_err);
 
ev_base = event_base_new();
if (!ev_base) {
    exit(EXIT_FAILURE);
}
static void event_fatal_err(int err)
{
    exit(EXIT_FAILURE);
}

После чего подготавливаем сокет.

/* Подготавливаем сокет */
memset((void *) &server_sock, 0, sizeof(server_sock));
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = INADDR_ANY;
server_sock.sin_port = htons(31245); /* номер порта */
/* bind'им сокет */
ev_listener = evconnlistener_new_bind(ev_base,
                                      accept_connection_cb, /* будет вызвана при попытки подключения*/
                                      NULL,                 /* можно передать данные в callback-функцию */
                                      (LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE),
                                      -1,
                                      (struct sockaddr *) &server_sock,
                                      sizeof(server_sock));
if(!ev_listener) {
    exit(EXIT_FAILURE);
}

И запускаем обработчик событий:

/* обработчик */
return event_base_dispatch(ev_base);

 

Теперь при попытке подключения будет вызываться функция:

static void accept_connection_cb(struct evconnlistener *listener,
                                 evutil_socket_t fd, struct sockaddr *addr, int sock_len,
                                 void *arg)
{
    struct bufferevent *ev_buf;
    struct timeval timeout;
    int ret;
    /* Создаем сокет для подключения */
    ev_buf = bufferevent_socket_new(ev_base, fd, BEV_OPT_CLOSE_ON_FREE);
    if (ev_buf == NULL) {
        exit(EXIT_FAILURE);
    }
    /* Устанавливаем callback-функции */
    bufferevent_setcb(ev_buf,
                      socket_read_cb,     /* callback чтения*/
                      NULL,               /* callback записи*/
                      error_callback,     /* callback ошибки*/
                      NULL);              /* в callback-функции можно передать данные */
 
    /* устанавливаем таймаут */
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;
    bufferevent_set_timeouts(ev_buf, &timeout, NULL);
    /* Активируем событие */
    ret = bufferevent_enable(ev_buf, EV_READ);
    if (ret < 0) {
        bufferevent_free(ev_buf);
        exit(EXIT_FAILURE);
    }
}

Теперь напишем callback-функции чтения и обработки ошибок:

static void error_callback(struct bufferevent *bev, short error, void *ctx)
{
    if(error & BEV_EVENT_READING) {
        /* в случае ошибки чтения аварийно завершаем программу*/
        exit(EXIT_FAILURE);
    }
}
 
static void socket_read_cb(struct bufferevent *bev, void *ctx)
{
    size_t ret;
    int chunk;
    /* Читаем даные из буфера */
    ret = bufferevent_read(bev, &chunk, sizeof(chunk));
    if(ret != sizeof(chunk)) {
        exit(EXIT_FAILURE);
    }
    /* Пишем данные в буфер */
    ret = bufferevent_write(bev, &chunk, sizeof(chunk));
    if(ret != sizeof(chunk)) {
        exit(EXIT_FAILURE);
    }
}

На официальном сайте можно найти документацию, а так же книгу.

dreamway89

dreamway89 wrote 29 posts

Post navigation


Добавить комментарий

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>