libevent使用event事件触发服务端实例

struct event_base* m_base = event_base_new();
if (NULL == m_base)
{
    return 1;
}

首先是创建base,后面的event都是基于base,关联到base才能进入循环。

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
struct evconnlistener* m_listener = evconnlistener_new_bind(m_base, do_accept, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (NULL == m_listener)
{
    return 1;
}
event_base_dispatch(m_base);

这里使用了libevent提供的监听器,evconnlistener_new_bind这个函数做的事情比较多。
1.创建一个监听套接字,设置非阻塞,设置FD_CLOEXEC,设置SO_KEEPALIVE,设置SO_REUSEADDR
2.使用传入的server_addr进行bind
3.使用-1位置的参数做监听队列大小,如果传入的值例如-1小于0,那么libevent使用128,如果大于0则使用这个大于0的值开始listen
4.当有新的连接时,创建套接字accept,并把套接字设置非阻塞,最后调用do_accept,把这个套接字和用户自定义变量等一系列值传给do_accept。
接下来就是为这个新的连接创建事件和设置我们关心的事件和回调函数了。

void do_accept(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sa, int socklen, void *ctx)
{
    //不使用Nagle算法,选择立即发送数据而不是等待产生更多的数据然后再一次发送
    int optval = 1;
    setsockopt(fd, SOL_SOCKET, TCP_NODELAY, &optval, sizeof(optval));
    struct event* ev = event_new(m_base, fd, EV_READ | EV_PERSIST, do_read, ctx);
    if (NULL == ev)
    {
        return 1;
    }
    event_add(ev, NULL);
}

在event_new中我们把事件ev和套接字fd关联起来放到了m_base循环中,关心的事件是有数据可读的事件,触发事件的回调函数是do_read,它的规定格式如下
void do_read(evutil_socket_t fd, short ev, void *ctx);
在do_read函数中一般的做法就是read数据到数据缓冲区,等待处理线程从数据缓冲区取数据然后处理,就是之前说的生产者消费者模式了。

你可能感兴趣的:(网络编程)