libevent实现http server

    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(evconnlistener_get_base(listener),
                               fd,
                               addres
  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
libevent是一个开源的事件驱动库,可以用来开发高并发的网络应用程序。下面是一个使用libevent实现的简单的HTTP服务器示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <event2/event.h> #include <event2/http.h> void http_cb(struct evhttp_request *req, void *arg) { const char *uri = evhttp_request_get_uri(req); printf("Request URI: %s\n", uri); struct evbuffer *evb = evbuffer_new(); if (evb == NULL) { fprintf(stderr, "Failed to create evbuffer\n"); evhttp_send_error(req, HTTP_INTERNAL, "Internal Server Error"); return; } evbuffer_add_printf(evb, "Hello World!"); evhttp_send_reply(req, HTTP_OK, "OK", evb); evbuffer_free(evb); } int main(int argc, char *argv[]) { struct event_base *base = event_base_new(); if (base == NULL) { fprintf(stderr, "Failed to create event_base: %s\n", strerror(errno)); return EXIT_FAILURE; } struct evhttp *httpd = evhttp_new(base); if (httpd == NULL) { fprintf(stderr, "Failed to create evhttp: %s\n", strerror(errno)); return EXIT_FAILURE; } if (evhttp_bind_socket(httpd, "0.0.0.0", 8080) != 0) { fprintf(stderr, "Failed to bind to 0.0.0.0:8080: %s\n", strerror(errno)); return EXIT_FAILURE; } evhttp_set_cb(httpd, "/", http_cb, NULL); printf("HTTP server started on 0.0.0.0:8080\n"); event_base_dispatch(base); evhttp_free(httpd); event_base_free(base); return EXIT_SUCCESS; } ``` 这个HTTP服务器监听本地8080端口,处理根路径的请求,返回"Hello World!"。可以使用curl命令测试: ``` $ curl http://localhost:8080/ Hello World! ``` 这只是一个简单的示例,实际的HTTP服务器需要更多的功能和处理逻辑。libevent提供了丰富的API和事件处理机制,可以很方便地实现高并发、高性能的网络应用程序。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

foruok

你可以选择打赏

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

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

打赏作者

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

抵扣说明:

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

余额充值