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); } }
На официальном сайте можно найти документацию, а так же книгу.