Libevent安装与使用(一)

时间:2022-09-16 00:14:33

What the lowest level of the Libevent API does:
  Provides a consistent interface to various select() replacements, using the most efficient version available on the computer where it’s running.

Libevent安装

1. 在官网上下载对应版本的包
2. tar -zxvf /your path/libevent-xxxx-stable.tar.gz解压
3. cd libevent-xxxx-stable
4. ./configure
5. make && make install
6. 在/usr/local/lib目录下将动态库的符号连接复制到/usr/lib/(这是为了防止在系统找不到库文件)

headers:
event2/event.h
event2/bufferevent.h

 

示例源码

 

Libevent安装与使用(一)

 

/**************************************************/

evutil_socket_t    //socket 文件描述符类型

int evutil_make_socket_nonblocking(evutil_socket_t sock);

It sets O_NONBLOCK on Unixand FIONBIO on Windows.

int evutil_make_listen_socket_reuseable(evutil_socket_t sock);

It sets SO_REUSEADDR on Unix and does nothing on Windows.

/**************************************************/

struct event_base *event_base_new(void);

  The event_base_new() function allocates and returns a new event base with the default settings. It examines the environment
variables and returns a pointer to a new event_base. If there is an error, it returns NULL.
When choosing among methods, it picks the fastest method that the OS supports.
function is declared in <event2/event.h>.

/**************************************************/

void event_base_free(struct event_base *base);


  When you are finished with an event_base, you can deallocate it with event_base_free().
Note that this function does not deallocate any of the events that are currently associated with the event_base, or close any of
their sockets, or free any of their pointers.

/**************************************************/

#define EVLOOP_ONCE 0x01
#define EVLOOP_NONBLOCK 0x02
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04

int event_base_loop(struct event_base *base, int flags);

  By default, the event_base_loop() function runs an event_base until there are no more events registered in it. To run the loop,
it repeatedly checks whether any of the registered events has triggered (for example, if a read event’s file descriptor is ready to
read, or if a timeout event’s timeout is ready to expire). Once this happens, it marks all triggered events as "active", and starts to
run them.

If EVLOOP_ONCE is set,
  then the loop will wait until some events become active, then run active events until there are no more to run, then return.

IfEVLOOP_NONBLOCK is set,
  then the loop will not wait for events to trigger: it will only check whether any events are ready
  to trigger immediately, and run their callbacks if so.

 

  Ordinarily, the loop will exit as soon as it has no pending or active events.You can override this behavior by passing the
EVLOOP_NO_EXIT_ON_EMPTY flag---for example, if you’re going to be adding events from some other thread. If you
do set EVLOOP_NO_EXIT_ON_EMPTY, the loop will keep running until somebody calls event_base_loopbreak(), or calls
event_base_loopexit(), or an error occurs.

When it is done, event_base_loop() returns 0 if it exited normally, -1 if it exited because of some unhandled error in the backend,
and 1 if it exited because there were no more pending or active events.

伪代码:

while (any events are registered with the loop,or EVLOOP_NO_EXIT_ON_EMPTY was set) {
if (EVLOOP_NONBLOCK was set, or any events are already active)
If any registered events have triggered, mark them active.
else
Wait until at least one event has triggered, and mark it active.
for (p = 0; p < n_priorities; ++p) {
if (any event with priority of p is active) {
Run all active events with priority of p.
break; /* Do not run any events of a less important priority */
}
}
if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)
break;
}

/**************************************************/

int event_base_dispatch(struct event_base *base);

  The event_base_dispatch() call is the same as event_base_loop(), with no flags set. Thus, it keeps running until there are no more
registered events or until event_base_loopbreak() or event_base_loopexit() is called.

/**************************************************/

If you want an active event loop to stop running before all events are removed from it, you have two slightly different functions
you can call.

int event_base_loopexit(struct event_base *base,
              const struct timeval *tv);
int event_base_loopbreak(struct event_base *base);

  The event_base_loopexit() function tells an event_base to stop looping after a given time has elapsed. If the tv argument is
NULL, the event_base stops looping without a delay. If the event_base is currently running callbacks for any active events, it
will continue running them, and not exit until they have all been run.
The event_base_loopbreak() function tells the event_base to exit its loop immediately. It differs from event_base_loopexit(base,
NULL) in that if the event_base is currently running callbacks for any active events, it will exit immediately after finishing the
one it’s currently processing

Note also that event_base_loopexit(base,NULL) and event_base_loopbreak(base) act differently when no event loop is running:
loopexit schedules the next instance of the event loop to stop right after the next round of callbacks are run (as if it had been
invoked with EVLOOP_ONCE) whereas loopbreak only stops a currently running loop, and has no effect if the event loop isn’t
running.

Both of these methods return 0 on success and -1 on failure.

/**************************************************/

#define EV_TIMEOUT 0x01    //This flag indicates an event that becomes active after a timeout elapses.
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08    //Used to implement signal detection. See "Constructing signal events"
#define EV_PERSIST 0x10    //Indicates that the event is persistent. See "About Event Persistence" below
#define EV_ET 0x20    //Indicates that the event should be edge-triggered, if the underlying event_base backend supports edge-triggered events.
             //This affects the semantics of EV_READ and EV_WRITE
typedef void (*event_callback_fn)(evutil_socket_t, short, void *); struct event *event_new(struct event_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void *arg);

The event_new() function tries to allocate and construct a new event for use with base. The what argument is a set of the flags
listed above. (Their semantics are described below.) If fd is nonnegative, it is the file that we’ll observe for read or write events.
When the event is active, Libevent will invoke the provided cb function, passing it as arguments: the file descriptor fd, a bitfield
of all the events that triggered, and the value that was passed in for arg when the function was constructed.
On an internal error, or invalid arguments, event_new() will return NULL.
All new events are initialized and non-pending. To make an event pending, call event_add() (documented below).
To deallocate an event, call event_free(). It is safe to call event_free() on an event that is pending or active: doing so makes the
event non-pending and inactive before deallocating it.

About Event Persistence
By default, whenever a pending event becomes active (because its fd is ready to read or write, or because its timeout expires),
it becomes non-pending right before its callback is executed. Thus, if you want to make the event pending again, you can call
event_add() on it again from inside the callback function.
If the EV_PERSIST flag is set on an event, however, the event is persistent. This means that event remains pending even when
its callback is activated. If you want to make it non-pending from within its callback, you can call event_del() on it

/**************************************************/

int event_assign(struct event *event, 
          struct event_base *base,
          evutil_socket_t fd,
          short what,           void (*callback)(evutil_socket_t, short, void *), void *arg);

All the arguments of event_assign() are as for event_new(), except for the event argument, which must point to an uninitialized
event. It returns 0 on success, and -1 on an internal error or bad arguments.

示例:

struct event *ev = event_new(NULL, -1, 0, NULL, NULL);
event_assign(ev, base, sockfd, EV_READ | EV_PERSIST,socket_read_cb, (void*)ev);

/**************************************************/

int event_add(struct event *ev, const struct timeval *tv);

Calling event_add on a non-pending event makes it pending in its configured base. The function returns 0 on success, and -1 on
failure. If tv is NULL, the event is added with no timeout. Otherwise, tv is the size of the timeout in seconds and microseconds.
If you call event_add() on an event that is already pending, it will leave it pending, and reschedule it with the provided timeout.
If the event is already pending, and you re-add it with the timeout NULL, event_add() will have no effect.

Do not set tv to the time at which you want the timeout to run. If you say "tv->tv_sec = time(NULL)+10;" on 1 January 2010,
your timeout will wait 40 years, not 10 seconds.

正确用法:

struct timeval ten_sec;
ten_sec.tv_sec = 10;
ten_sec.tv_usec = 0;
event_add(ev, &ten_sec)

 

/**************************************************/

int event_del(struct event *ev);

Calling event_del on an initialized event makes it non-pending and non-active. If the event was not pending or active, there is no
effect. The return value is 0 on success, -1 on failure.

If you delete an event after it becomes active but before its callback has a chance to execute, the callback will not be executed.

 

/**************************************************/

 

void *event_self_cbarg();

 

The event_self_cbarg() function returns a "magic" pointer which, when passed as an event callback argument, tells event_new()
to create an event receiving itself as its callback argument.

 

 

/**************************************************/

 

#ifdef WIN32
int evthread_use_windows_threads(void);
#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
#endif
#ifdef _EVENT_HAVE_PTHREADS
int evthread_use_pthreads(void);
#define EVTHREAD_USE_PTHREADS_IMPLEMENTED
#endif

 

If you are using the pthreads library, or the native Windows threading code, you’re in luck. There are pre-defined functions that
will set Libevent up to use the right pthreads or Windows functions for you.

 

Both functions return 0 on success, and -1 on failure.

 

 

/**************************************************/

enum event_method_feature 
{
EV_FEATURE_ET = 0x01,    //要求支持边沿触发的后端
EV_FEATURE_O1 = 0x02,    //要求添加、删除单个事件,或者确定哪个事件激活的操作是O(1)复杂度的后端
EV_FEATURE_FDS = 0x04,    //要求支持任意文件描述符,而不仅仅是套接字的后端
};
int event_config_require_features(struct event_config *cfg,enum event_method_feature feature);
//让 libevent不使用不能提供所有指定特征的后端


int evutil_make_listen_socket_reuseable(evutil_socket_t sock);

This function makes sure that the address used by a listener socket will be available to another socket immediately after the
socket is closed. (It sets SO_REUSEADDR on Unix and does nothing on Windows. You don’t want to use SO_REUSEADDR
on Windows; it means something different there.)

/**************************************************/

tips:
  非阻塞IO:如果输入操作不能被满足(TCP没有一个字节到达,UDP没有一个数据报可读)则输入操作返回-1 并设置EWOULDBLCOK错误;如果TCP连接被关闭,则输入操作返回0;如果UDP收到长度为0的数据报,则输入操作返回0;
  对于TCP输出操作,如果发送缓冲区没有空间,则返回-1 并设置EWOULDBLCOK错误;如果发动缓冲区有不足的空间,则返回内核能够复制到该缓冲区的字节数,即不足字节数。
在某些系统中EWOULDBLCOK和EAGAIN值相同