libevent实现http server

本文介绍了如何使用libevent库构建一个简单的HTTP服务器,包括监听、启动事件循环、接受连接、解析HTTP请求和响应客户端。示例代码仅支持GET方法,不支持Range请求,适用于学习libevent的网络编程。

    libevent 是一个事件触发的网络库,适用于 windows、linux、bsd 、Android 等多种平台,内部使用 select、epoll、kqueue 、完成端口等系统调用管理事件机制。著名分布式缓存软件 memcached 也是 libevent based 。

    最近在学习 libevent ,之前基于 libevent 实现了一个 http client ,没有用到 bufferevent 。这次实现了一个 http server ,很简单,只支持 GET 方法,不支持 Range 请求,但完全自己实现,是一个完整可用的示例。这里使用 libevent-2.1.3-alpha 。

    我关于 libevent 的其它文章,列在这里供参考:

    使用 libevent 实现一个 http server ,有这么几个步骤:

  1. 监听
  2. 启动事件循环
  3. 接受连接
  4. 解析 http 请求
  5. 回应客户端

    关于监听, libevent 提供了 evconnlistener ,使用起来非常简单,通过一些设置,调用 evconnlistener_new_bind 即可完成一个服务端 socket 的创建,可以参考官方文档Connection Listeners 。下面是启动 server 的代码:

int start_http_server(struct event_base *evbase)
{
    int bind_times = 0;
    struct sockaddr_in sin;

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
#ifdef WIN32
    sin.sin_addr.S_un.S_addr = inet_addr(g_host);
#else
    sin.sin_addr.s_addr = inet_addr(g_host);
#endif
    sin.sin_port = htons(g_port);

trybind:
    g_listener = evconnlistener_new_bind(
                evbase, _accept_connection, 0,
                LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_DEFERRED_ACCEPT, -1,
                (struct sockaddr*)&sin, sizeof(sin));
    if (!g_listener)
    {
        if(bind_times++ >=3)
        {
            printf("couldn\'t create listener\n");
            return 1;
        }
        else
        {
            sin.sin_port = 0;
            goto trybind;
        }
    }
    else if(bind_times > 0)
    {
        socklen_t len = sizeof(sin);
        getsockname(evconnlistener_get_fd(g_listener),
                    (struct sockaddr*)&sin, &len);
        g_port = ntohs(sin.sin_port);
    }
    evconnlistener_set_error_cb(g_listener, _accept_error_cb);

    return 0;
}

    关于事件循环,event_base_new 可以创建一个 event_base 实例, event_base_loop 可以进入事件循环。下面是 main() 函数中关于事件循环的代码:

    g_evbase = event_base_new();

    if( 0 == start_http_server(g_evbase) )
    {
        event_base_loop(g_evbase, EVLOOP_NO_EXIT_ON_EMPTY);
        printf("httpserver exit now.\n");
    }
    else
    {
        printf("httpserver, start server failed\n");
    }

    event_base_free(g_evbase);
    上面的代码中,启动事件循环时传递了一个标志 EVLOOP_NO_EXIT_ON_EMPTY ,对于服务器程序,这是必须的,否则在没有待处理事件时,事件循环会立即退出。

    通过给 evconnlistener 设置一些回调,就可以接受连接、处理错误。下面是相关代码:

static void _accept_connection(struct evconnlistener *listener,
                               evutil_socket_t fd, struct sockaddr *addr
                               , int socklen, void * ctx)
{
    char address[64];
    struct http_connection *conn;
    struct sockaddr_in sin;
    short port = 0;
    /* get address and port*/
    memcpy(&sin, addr, sizeof(sin));
    sprintf(address, "%s", inet_ntoa(sin.sin_addr));
    port = ntohs(sin.sin_port);
#ifdef HTTP_SERVER_DEBUG
    printf("httpserver, accept one connection from %s:%d\n", address, port);
#endif
    conn = new_http_connection(evconnlisten
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

foruok

你可以选择打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值