libevent源码剖析(二)

struct evconnlistener *
evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,
    void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,
    int socklen)
{
/*
共7个入参:
@base  --base指针;
@cb  --监听回调,当监听的事件触发时执行;
@ptr  --一个空指针类型,这里是将base指针强转后传入;
@flags  --监听标志(选项),通常会设置地址复用等标志;
@backlog  --连接队列最大长度,填"-1"默认128;
@sa  --服务端socket地址;
@socklen  --地址长度;


*/
    //1.先准备一个监听器指针
    struct evconnlistener *listener;

    /*
    2.创建套接字:
        --设置协议族
        --设置协议名和非阻塞
    */
    evutil_socket_t fd;
    int on = 1;
    int family = sa ? sa->sa_family : AF_UNSPEC;
    int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;//TCP,非阻塞

    if (backlog == 0)
        return NULL;
    //内部调用exec()前关闭此文件描述符;
    if (flags & LEV_OPT_CLOSE_ON_EXEC)
        socktype |= EVUTIL_SOCK_CLOEXEC;

    fd = evutil_socket_(family, socktype, 0);
    if (fd == -1)
        return NULL;

    //3.给套接字设置心跳检测
    if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)
        goto err;

    //4.给套接字设置地址复用
    if (flags & LEV_OPT_REUSEABLE) {
        if (evutil_make_listen_socket_reuseable(fd) < 0)
            goto err;
    }

    //5.给套接字设置端口复用
    if (flags & LEV_OPT_REUSEABLE_PORT) {
        if (evutil_make_listen_socket_reuseable_port(fd) < 0)
            goto err;
    }

    if (flags & LEV_OPT_DEFERRED_ACCEPT) {
        if (evutil_make_tcp_listen_socket_deferred(fd) < 0)
            goto err;
    }

    if (flags & LEV_OPT_BIND_IPV6ONLY) {
        if (evutil_make_listen_socket_ipv6only(fd) < 0)
            goto err;
    }
    //6.给套接字绑定地址
    if (sa) {
        if (bind(fd, sa, socklen)<0)
            goto err;
    }
    
    /*7.
        入参:event_base指针、监听回调、event_base的空指针类型、监听队列长度、已初始化的套接字;
        返回:一个可用的“监听器”指针;
    */
    listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);
    if (!listener)
        goto err;

    return listener;
err:
    evutil_closesocket(fd);
    return NULL;
}
原文地址:https://www.cnblogs.com/orejia/p/12349105.html