libevent相关基础

libevent是一个老牌的服务器底层引擎。质量还是非常好的。基本上很多不想编写服务器底层的团队都会选用这个底层。毕竟写一套出来,代码还是那些东西。

windows debug开启

打开libevent的目录,找到Makefile.nmake文件。这个文件是用于做windows下nmake工具的makefile文件。
这里写图片描述

CFLAGS=$(CFLAGS) /DUSE_DEBUG /Zi /Ox /W3 /wd4996 /nologo

这里写图片描述
修改“event_iocp.c”、“evthread_win32.c”、“listener.c”三个文件,在文件开头重新定义系统版本号:

#define _WIN32_WINNT 0x0500

默认定义为

#define _WIN32_WINNT 0x0403

备注系统对应关系:

Windows   XP                                      _WIN32_WINNT>=0x0501     
Windows   2000                                   _WIN32_WINNT>=0x0500     
Windows   NT   4.0                               _WIN32_WINNT>=0x0400     
Windows   Me                                      _WIN32_WINDOWS=0x0490     
Windows   98                                      _WIN32_WINDOWS>=0x0410   
//  
// _WIN32_WINNT version constants  
//  
#define _WIN32_WINNT_NT4                    0x0400 // Windows NT 4.0  
#define _WIN32_WINNT_WIN2K                  0x0500 // Windows 2000  
#define _WIN32_WINNT_WINXP                  0x0501 // Windows XP  
#define _WIN32_WINNT_WS03                   0x0502 // Windows Server 2003  
#define _WIN32_WINNT_WIN6                   0x0600 // Windows Vista  
#define _WIN32_WINNT_VISTA                  0x0600 // Windows Vista  
#define _WIN32_WINNT_WS08                   0x0600 // Windows Server 2008  
#define _WIN32_WINNT_LONGHORN               0x0600 // Windows Vista  
#define _WIN32_WINNT_WIN7                   0x0601 // Windows 7  
#define _WIN32_WINNT_WIN8                   0x0602 // Windows 8  
#define _WIN32_WINNT_WINBLUE                0x0603 // Windows 8.1  
#define _WIN32_WINNT_WINTHRESHOLD           0x0A00 // Windows 10  
#define _WIN32_WINNT_WIN10                  0x0A00 // Windows 10  

在使用过程中如果你想去调试他的时候可以通过里面自带的调试日志接口,将他的日志接管,然后输出出来:

void libevent_log_callback(int severity, const char *msg)
{
    printf("[libEvent] debug Level: %d, msg: %s\n", severity, msg);
}

event_set_log_callback(libevent_log_callback);

编译方式

nmake /f Makefile.nmake

这里写图片描述

使用libevent连接

这里是参考libevent中的test中的openssl的源码。

        struct bufferevent                                  *bev_;
        evutil_socket_t                                     fd_;
        struct sockaddr_in in;
        if ((fd_ = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            printf("[NET] create socket fail");
            return -1;
        }

        memset(&in,0, sizeof(struct sockaddr_in));
        in.sin_family = AF_INET;
        in.sin_addr.s_addr = inet_addr(_remote_ip);
        in.sin_port = htons(_remote_port);

        bev_ = bufferevent_socket_new(base_
            , fd_, BEV_OPT_CLOSE_ON_FREE);

        if (bev_ == NULL) {
            printf( "[NET] bufferevent_socket_new fail.");
            return -1;
        }
        bufferevent_setcb(bev_, &on_session_read, NULL
            , &on_session_event, NULL);

        if (bufferevent_socket_connect(session->bev_, (struct sockaddr *)&in, sizeof(in)) != 0) {
            print("[NET] failed.");
            return -1;
        }

回调函数:


void on_session_event(struct bufferevent *bev, short error, void *ctx)
{
    if (error & BEV_EVENT_CONNECTED)
    {
        // 异步连接socket已经成功了
        return;
    }
    ...
}

使用iocp

可以阅读event.c文件中的


struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
...
#ifdef WIN32
    if (cfg && (cfg->flags & EVENT_BASE_FLAG_STARTUP_IOCP))
        event_base_start_iocp(base, cfg->n_cpus_hint);
#endif


int
event_base_start_iocp(struct event_base *base, int n_cpus)
{
#ifdef WIN32
    if (base->iocp)
        return 0;
    base->iocp = event_iocp_port_launch(n_cpus);
    if (!base->iocp) {
        event_warnx("%s: Couldn't launch IOCP", __func__);
        return -1;
    }
    return 0;
#else
    return -1;
#endif
}

其实这个也依赖于在创建event_base这个数据结构的时候自己要创建一个cfg的数据结构。将其中n_cpus(当前机器的cpu个数)设置好,cfg->flags 设置上 EVENT_BASE_FLAG_STARTUP_IOCP标记。
event_iocp.c文件中:


#define N_CPUS_DEFAULT 2

struct event_iocp_port *
event_iocp_port_launch(int n_cpus)
{
    struct event_iocp_port *port;
    int i;

    if (!extension_fns_initialized)
        init_extension_functions(&the_extension_fns);

    if (!(port = mm_calloc(1, sizeof(struct event_iocp_port))))
        return NULL;

    if (n_cpus <= 0)
        n_cpus = N_CPUS_DEFAULT;
    port->n_threads = n_cpus * 2;
    port->threads = mm_calloc(port->n_threads, sizeof(HANDLE));
    if (!port->threads)
        goto err;

    port->port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,
            n_cpus);
    port->ms = -1;
    if (!port->port)
        goto err;

    port->shutdownSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
    if (!port->shutdownSemaphore)
        goto err;

    for (i=0; i<port->n_threads; ++i) {
        ev_uintptr_t th = _beginthread(loop, 0, port);
        if (th == (ev_uintptr_t)-1)
            goto err;
        port->threads[i] = (HANDLE)th;
        ++port->n_live_threads;
    }

    InitializeCriticalSectionAndSpinCount(&port->lock, 1000);

    return port;
err:
    if (port->port)
        CloseHandle(port->port);
    if (port->threads)
        mm_free(port->threads);
    if (port->shutdownSemaphore)
        CloseHandle(port->shutdownSemaphore);
    mm_free(port);
    return NULL;
}

在这段代码里面将会为event_base创建好完成端口数据结构,信号量,创建工作线程。
更多的细节还需要多阅读它的源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值