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