古月不傲 发表于 2020-11-10 13:32

libevent中的helloworld示例

本帖最后由 古月不傲 于 2020-11-10 13:37 编辑

/*
This example program provides a trivial server program that listens for TCP
connections on port 9995.When they arrive, it writes a short message to
each client connection, and closes each connection once it is flushed.

Where possible, it exits cleanly in response to a SIGINT (ctrl-c).
*/


#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#ifndef _WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#include <arpa/inet.h>
# endif
#include <sys/socket.h>
#endif

#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>

static const char MESSAGE[] = "Hello, World!\n";

static const int PORT = 9995;

static void listener_cb(struct evconnlistener *, evutil_socket_t,
    struct sockaddr *, int socklen, void *);
static void conn_writecb(struct bufferevent *, void *);
static void conn_eventcb(struct bufferevent *, short, void *);
static void signal_cb(evutil_socket_t, short, void *);
static void read_cb(struct bufferevent *bev, void *ctx);
int
main(int argc, char **argv)
{
      struct event_base *base;
      struct evconnlistener *listener;
      struct event *signal_event;

      struct sockaddr_in sin = {0};
#ifdef _WIN32
      WSADATA wsa_data;
      WSAStartup(0x0201, &wsa_data);
#endif
      // 分配event_base
      base = event_base_new();
      if (!base) {
                fprintf(stderr, "Could not initialize libevent!\n");
                return 1;
      }
      sin.sin_family = AF_INET;
      sin.sin_port = htons(PORT);
      // socket bind listen accpet
      listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
            LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
            (struct sockaddr*)&sin,
            sizeof(sin));
      if (!listener) {
                fprintf(stderr, "Could not create a listener!\n");
                return 1;
      }
      
      // 关联一个中断事件
      signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
      // 等待signal_event事件发生 NULL=永久等待 当按下ctrl+c触发中断
      if (!signal_event || event_add(signal_event, NULL)<0) {
                fprintf(stderr, "Could not create/add a signal event!\n");
                return 1;
      }
      // 循环监听event_base事件
      event_base_dispatch(base);


      // 释放
      evconnlistener_free(listener);
      event_free(signal_event);
      event_base_free(base);

      printf("done\n");
      return 0;
}

// 监听客户端的到来回调
static void
listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sa, int socklen, void *user_data)
{
      struct event_base *base = user_data;
      struct bufferevent *bev;
    // 创建event读写缓冲
      bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
      if (!bev) {
                fprintf(stderr, "Error constructing bufferevent!");
                event_base_loopbreak(base);
                return;
      }
    // 设置回调
      bufferevent_setcb(bev, read_cb, conn_writecb, conn_eventcb, NULL);
      bufferevent_enable(bev, EV_WRITE);// 使可写
      bufferevent_enable(bev, EV_READ);   // 使可读

      //bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
}

// 读回调
static void read_cb(struct bufferevent *bev, void *ctx)
{
      char buf = {};
      bufferevent_read(bev, buf, 1024);
      printf("buf=%s\n", buf);
    bufferevent_write(bev, buf, sizeof(buf));
}

// 写回调
static void
conn_writecb(struct bufferevent *bev, void *user_data)
{
      struct evbuffer *output = bufferevent_get_output(bev);
      if (evbuffer_get_length(output) == 0) {
                //printf("flushed answer\n");
                //bufferevent_free(bev);
      }
}

// 连接中的事件回调
static void
conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
      if (events & BEV_EVENT_EOF) {
                printf("Connection closed.\n");
      } else if (events & BEV_EVENT_ERROR) {
                printf("Got an error on the connection: %s\n",
                  strerror(errno));/*XXX win32*/
      }
      /* None of the other events can happen here, since we haven't enabled
         * timeouts */
      bufferevent_free(bev);
}

// 事件回调
static void
signal_cb(evutil_socket_t sig, short events, void *user_data)
{
      struct event_base *base = user_data;
      struct timeval delay = { 2, 0 };

      printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");

      // 两秒后结束循环监听
      event_base_loopexit(base, &delay);
}
/**
Allocate and assign a new event structure, ready to be added.

The function event_new() returns a new event that can be used in
future calls to event_add() and event_del().The fd and events
arguments determine which conditions will trigger the event; the
callback and callback_arg arguments tell Libevent what to do when the
event becomes active.

If events contains one of EV_READ, EV_WRITE, or EV_READ|EV_WRITE, then
fd is a file descriptor or socket that should get monitored for
readiness to read, readiness to write, or readiness for either operation
(respectively).If events contains EV_SIGNAL, then fd is a signal
number to wait for.If events contains none of those flags, then the
event can be triggered only by a timeout or by manual activation with
event_active(): In this case, fd must be -1.

The EV_PERSIST flag can also be passed in the events argument: it makes
event_add() persistent until event_del() is called.

The EV_ET flag is compatible with EV_READ and EV_WRITE, and supported
only by certain backends.It tells Libevent to use edge-triggered
events.

The EV_TIMEOUT flag has no effect here.

It is okay to have multiple events all listening on the same fds; but
they must either all be edge-triggered, or all not be edge triggered.

When the event becomes active, the event loop will run the provided
callback function, with three arguments.The first will be the provided
fd value.The second will be a bitfield of the events that triggered:
EV_READ, EV_WRITE, or EV_SIGNAL.Here the EV_TIMEOUT flag indicates
that a timeout occurred, and EV_ET indicates that an edge-triggered
event occurred.The third event will be the callback_arg pointer that
you provide.

@param base the event base to which the event should be attached.
@param fd the file descriptor or signal to be monitored, or -1.
@param events desired events to monitor: bitfield of EV_READ, EV_WRITE,
      EV_SIGNAL, EV_PERSIST, EV_ET.
@param callback callback function to be invoked when the event occurs
@param callback_arg an argument to be passed to the callback function

@return a newly allocated struct event that must later be freed with
    event_free() or NULL if an error occurred.
@see event_free(), event_add(), event_del(), event_assign()
*/

#define evsignal_new(b, x, cb, arg)                              \
      event_new((b), (x), EV_SIGNAL|EV_PERSIST, (cb), (arg))
EVENT2_EXPORT_SYMBOL
struct event *event_new(struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg);
功能:
    分配一个新的event事件 用完要event_free()
参数:
    base:         要关联的event_base指针
    fd            要监听的文件描述符,如果什么事件都不指定,必须设置为-1
    events:         事件类型
      EV_READ:      读事件
      EV_WRITE:       写事件
      EV_PERSIST:   逗留事件 处理完以后不丢弃 需要调用event_del()
      EV_TIMEOUT:   超时事件
      EV_ET:          边缘触发事件
      EV_SIGNAL:      信号事件
      EV_CLOSED:   连接关闭事件
    callback:       回调函数   
    callback_arg:   回调参数
回调函数:
    typedef void (*event_callback_fn)(evutil_socket_t, short, void *);
    fd:   文件描述符或信号   
    events: 事件类型   
    arg:    用户参数   

/**
   Allocate a new evconnlistener object to listen for incoming TCP connections
   on a given address.

   @param base The event base to associate the listener with.
   @param cb A callback to be invoked when a new connection arrives. If the
      callback is NULL, the listener will be treated as disabled until the
      callback is set.
   @param ptr A user-supplied pointer to give to the callback.
   @param flags Any number of LEV_OPT_* flags
   @param backlog Passed to the listen() call to determine the length of the
      acceptable connection backlog.Set to -1 for a reasonable default.
   @param sa The address to listen for connections on.
   @param socklen The length of the address.
*/

EVENT2_EXPORT_SYMBOL
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
    const struct sockaddr *sa, int socklen);
功能:
    封装socket(), bind(), listen(), accept() 用完记得evconnlistener_free()
参数:
    base:       要关联的event_base指针
    cb:         一个客户端连接到来的回调函数   
    ptr:      回调参数
    flags:      LEV_OPT_*
    backlog:    最大连接队列,-1默认合理值
    sa:         struct sockaddr
    socklen:    struct sockaddr长度
回调函数:
    typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *);
    @brief A callback that we invoke when a listener has a new connection.
    @param listener The evconnlistener
    @param fd The new file descriptor
    @param addr The source address of the connection
    @param socklen The length of addr
    @param user_arg the pointer passed to evconnlistener_new()

linuxcool 发表于 2020-11-11 12:21

楼主可不用它做一个线程池或者内存池
页: [1]
查看完整版本: libevent中的helloworld示例