libevent Note 2: Hello_World

Benpian Hello_World demo provides a brief introduction by libevent libevent Based on the TCP server

listener

libevent listener is to provide a listening port local data structure, call the given callback when the arrival of a customer connection side.

bufferevent

On one of the event is unbuffered area, directly read and write file descriptors in the object pointed to (is on a named pipe) is on. bufferent event with Buffer is, read and write operations bufferevnet not directly act on the I / O, but the input or output buffer operation. Bufferevent read operation would read corresponding input data from the file descriptor buffer; and write operations will write data to the file descriptor corresponding output buffer.

Hello_World

The following is the official website provides demo


#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 *);

int main(int argc, char **argv)
{
    struct event_base *base;
    struct evconnlistener *listener;
    struct event *signal_event;

    struct sockaddr_in sin;
#ifdef _WIN32
    WSADATA wsa_data;
    WSAStartup(0x0201, &wsa_data);
#endif

    base = event_base_new();
    if (!base) {
        fprintf(stderr, "Could not initialize libevent!\n");
        return 1;
    }

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    //create a listrener
    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);

    if (!signal_event || event_add(signal_event, NULL)<0) {
        fprintf(stderr, "Could not create/add a signal event!\n");
        return 1;
    }

    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_free(signal_event);
    event_base_free(base);

    printf("done\n");
    return 0;
}
//invoke when a connection is listened by listener created in main
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;
    //create a new bufferevent over a existing socket
    
    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, NULL, conn_writecb, conn_eventcb, NULL);
    bufferevent_enable(bev, EV_WRITE);//enable write to bev
    bufferevent_disable(bev, EV_READ);//disable read from bev
    
    bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
}

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);
}

Compile and run the file:

sunminming@sunminming:~/libevent/helloworld$ gcc helloworld.c -o main -levent
sunminming@sunminming:~/libevent/helloworld$ ./main

After open another terminal:

sunminming@sunminming:~$ nc 127.0.0.1 9995
Hello, World!

In a first terminal type the Ctrl + C :

sunminming@sunminming:~/libevent/helloworld$ gcc helloworld.c -o main -levent
sunminming@sunminming:~/libevent/helloworld$ ./main
flushed answer
^CCaught an interrupt signal; exiting cleanly in two seconds.
done
sunminming@sunminming:~/libevent/helloworld$ 

For this TCP server, the overall logic is as follows:

  • Create a event_base , then bound thereon a listener to listen to a specific port (9995);
  • New Event processing a signal signal_event , and the previous step event_base binding;
  • Call event_base_dispatch to monitor the two events, including the designation of a TCP connection and SIGINT signal:
    • When you are listening to a connection, libevent triggers listen_callback , that is, above listener_cb function, which first of all based on the socket underlying the establishment of a bufferevent, readable and writable, the last call bufferevent_write function to which the write buffer.
      • bufferevent_write function is triggered after the write-back write callback conn_writecb , this example, since no other operation, so conn_writecb function directly release the connection. (Write callback mechanism is more complex, concrete can see this blog )
    • When the interrupt signal (Ctrl + C) appears, libevent triggers signal_event callback function signal_cb , the function will stop after two seconds event_base monitor and return to the main function;
  • The main function in turn release listener , signal_event and event_base resources to end.

related functions

  • * evconnlistener_new_bind evconnlistener (struct event_base Base,
                           evconnlistener_cb CB,
                void
    PTR, the flags unsigned, int backlog,
                const struct the sockaddr * sa,
                int socklen):
    This function creates a evconnlistener structure, i.e. the listener to listen to a given address sa and then listen to a new client connects, the call cb function. Parameters are listed below:
    • struct event_base * base of the listener binding event_base ;
    • evconnlistener_cb cb callback connection;
    • void PTR provided to the callback function cb parameters, cb a total of five parameters: the first is a listener, a second socket for the client connection, and the third is the sockaddr structure representing the IP address of the client and port number, the fourth is socketaddr length, the fifth parameter is provided by the user, and ptr;
    • unsigned flags & ensp flag bits, LEV_OPT_REUSEABLE represents reuse the same port will not have time interval; LEV_OPT_CLOSE_ON_FREE represents a listener when released simultaneously release the underlying Socket;
    • int backlog generally set to -1;
    • const struct sockaddr * sa a sockaddr structure, comprising represents needs to listen to a local IP address and port number;
    • int socklen on a parameter sa length;
  • * bufferevent_socket_new bufferevent (struct event_base * Base,
             evutil_socket_t FD,
             int Options):
    This function is used to create a bufferevent structure. Parameters are listed below:
    • struct event_base * base the bufferevent structure bound event_base ;
    • evutil_socket_t fd underlying file descriptor to read and write, this parameter is not allowed to a pipe, allowing to -1, and then followed by another set function;
    • int options identifier, BEV_OPT_CLOSE_ON_FREE represents the release bufferevent release the underlying file descriptor;
  • int event_base_loopbreak ( struct event_base * eb ):
    • Immediately stop listening cycle, this function is usually invoked in the event of a callback function, it can be understood as an interrupt;
  • bufferevent_setcb void (* struct bufferevent bufev,
              bufferevent_data_cb readcb,
              bufferevent_data_cb writecb,
              bufferevent_event_cb eventcb,
              void * cbarg):
    This function is used to bufferevent setting read / event callback function. Parameters are listed below:
    • struct bufferevent * bufev need to set bufferevent ;
    • bufferevent_data_cb readcb read callback function, but the input buffer read data when calling, may be set to NULL ;
    • bufferevent_data_cb readcb write callback function, but the output buffer may write call, can be set to NULL ;
    • bufferevent_event_cb eventcb event callback function, but called when there are other events, it can be set to NULL ;
    • void * cbarg provided to the callback function of each parameter;
  • bufferevent_enable int / bufferevent_disable (struct bufferevent * bufev,
           Short Event):
    This function allow bufferevnet can be / can not be read or written. Parameters are listed below:
    • struct bufferevent * bufev the function operation bufferevent ;
    • any combination of read and write short event, EV_READ for read, EV_WRITE represents write, EV_READ | EV_WRITE represents read and write;
  • bufferevent_write int (* struct bufferevent bufev,
            const void * Data,
            size_t size):
    for the bufferevent write data output buffer, then the data is automatically written into the corresponding file descriptor. Parameters are listed below:
    • struct bufferevent * bufev needs to be written bufferevent ;
    • Data written const void * data;
    • size_t size of the write data length;

Guess you like

Origin www.cnblogs.com/sunminming/p/11862914.html