zoukankan      html  css  js  c++  java
  • Libevent官方代码样例学习(二)

    连接监听器: 接收TCP连接请求

    evconnlistener机制用于监听并接受TCP连接请求. 这些方法在event2/listener.h中声明, 在Libevent 2.0.2-alpha之后的版本中可用.

    创建和释放evconnlistener

    接口
    struct evconnlistener *evconnlistener_new(     struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, evutil_socket_t fd);
    struct evconnlistener *evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, const struct sockaddr *sa, int socklen);
    void evconnlistener_free(struct evconnlistener *lev);

    这两个 evconnlistener_new*() 方法都会allocate并返回一个新的connection listener对象. connection listener使用event_base 来通知来自于制定的socket上的新的TCP连接请求. 并调用预设的回调方法.

    这两个方法相同的参数:
    base 是listener用来监听的event_base.
    cb 是回调方法, 如果cb is NULL, listener会被视为禁用, 直到回调被设置.
    ptr 指针会作为参数被传递给回调方法.
    flags 参数控制listener的行为.
    backlog 参数控制允许的等待的连接数的上限. 如果backlog是负数, Libevent会自动设置一个合适的值, 如果为0, 则Libevent会认为你已经在socket上调用了listen()方法.

    这两个方法中不同的参数, 在于如何初始化listener socket. evconnlistener_new() 方法假定你已经在要监听的端口上绑定了socket, 你只需要传递socket的fd就够. 如果你希望Libevent自己allocate并绑定socket, 就调用evconnlistener_new_bind(), 并传入你想监听的的sockaddr和它的length.

    Tip
    [使用 evconnlistener_new时要确保监听的socket工作于non-blocking 状态, (用evutil_make_socket_nonblocking 或手工指定正确的socket选项). When the listening socket is left in blocking mode, undefined behavior might occur.]

    要释放一个 listener, 使用evconnlistener_free().

    创建一个signal events

    Libevent can also watch for POSIX-style signals. 要创建一个signal的handler, 使用接口:

    #define evsignal_new(base, signum, cb, arg)  event_new(base, signum, EV_SIGNAL|EV_PERSIST, cb, arg)

    可以看到其实是调用了event_new, 只不过flag是EV_SIGNAL|EV_PERSIST, 并且不是传fd而是传signum

    例子
    struct event *hup_event;
    struct event_base *base = event_base_new();
    
    /* call sighup_function on a HUP signal */
    hup_event = evsignal_new(base, SIGHUP, sighup_function, NULL);

    注意: signal回调在signal发生后, 在event loop中执行, 所以一些在常规POSIX信号handler中不能调用的方法是可以在这种情况下调用的.

    注意
    不要在signal event中设置timeout

    另外一些相关的宏设定:

    #define evsignal_add(ev, tv) 
        event_add((ev),(tv))
    #define evsignal_del(ev) 
        event_del(ev)
    #define evsignal_pending(ev, what, tv_out) 
        event_pending((ev), (what), (tv_out))

    evsignal_* 宏定义也是在Libevent 2.0.1-alpha之后的版本中可用.

    例子

    /*
      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>
    #include <event2/bufferevent.h>
    #include <event2/buffer.h>
    #include <event2/listener.h>
    
    static const char MESSAGE[] = "Hello, World!
    ";
    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;
    
        base = event_base_new();
        if (!base) {
            fprintf(stderr, "Could not initialize libevent!
    ");
            return 1;
        }
    
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
        sin.sin_port = htons(PORT);
        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!
    ");
            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!
    ");
            return 1;
        }
    
        event_base_dispatch(base);
        evconnlistener_free(listener);
        event_free(signal_event);
        event_base_free(base);
        printf("done
    ");
        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;
    
        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);
        bufferevent_disable(bev, EV_READ);
        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
    ");
            bufferevent_free(bev);
        }
    }
    
    static void
    conn_eventcb(struct bufferevent *bev, short events, void *user_data) {
        if (events & BEV_EVENT_EOF) {
            printf("Connection closed.
    ");
        } else if (events & BEV_EVENT_ERROR) {
            printf("Got an error on the connection: %s
    ", 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.
    ");
        event_base_loopexit(base, &delay);
    }
  • 相关阅读:
    eclipse注释模板设置(未整理)
    10大最适合编程的字体推荐下载,让代码看起来更美更舒服!
    系统里有Courier New字体 Eclipse没有这个字体选项
    Hadoop安装教程_集群/分布式配置
    Hadoop安装教程_单机/伪分布式配置
    VMware中三种网络连接的区别
    修改Tomcat的默认访问目录
    Ubuntu 16.04服务器 配置
    Ubuntu 16.04服务器 软件的安装及配置
    排序算法 -- 桶排序
  • 原文地址:https://www.cnblogs.com/milton/p/7981104.html
Copyright © 2011-2022 走看看