• 2014-04-12

    Libevent HTTP 内存泄露

    Views: 50741 | 3 Comments

    支持百万并发连接的 comet 推送服务器 icomet 刚刚修复了一个内存泄露的 bug, 这个 bug 是因为不正确地使用 libevent 导致的, 无法用 valgrind 等工具检查出来.

    这个 bug 的原因是这样的, 当客户端请求到来时, 服务器端调用了

    evhttp_send_reply_start();
    

    表示开始向客户端推送数据(使用 HTTP chunked), 最后当 long-polling 结束时, 应该调用

    evhttp_send_reply_end();
    

    来关闭连接, 释放 libevent 的内存. 不过, 如果客户端提前终止了请求, 会导致什么呢? 会导致连接关闭的回调函数 evhttp_connection_set_closecb() 被调用, 但是, 在这个回调函数里, 我没有调用 evhttp_send_reply_end(), 所以导致了内存泄露.

    在使用 libevent 的过程中, 发现 libevent 的坑确实不少, 而且它的文档根本没有对类似的地方做特别说明, 没有说明哪些函数必须配对使用, 如何释放内存等.

    Posted by ideawu at 2014-04-12 12:11:44 Tags: ,
  • 2013-09-18

    构建C1000K的服务器(2) – 实现百万连接的comet服务器

    Views: 92679 | 40 Comments

    这是关于 C1000K 序列文章的第二篇, 在前一篇文章 构建C1000K的服务器(1) – 基础 中, 介绍了支持 C1000K 的 Linux 系统的内核参数调整和系统设置. 在本篇文章中, 将对一个真正的应用服务器做 C1000K 测试.

    Comet 服务器是一类逻辑相对简单, 需要高并发连接的服务器. Comet 在网站系统中的应用非常广泛, 可以见这篇日志的介绍: http://www.ideawu.net/blog/archives/737.html.

    HTTP 协议处理

    要开发一个支持百万并发连接的 Comet 服务器, 我选择 C/C++ 语言, 当然还有其它的选择如 Erlang, Java 等. 对于一个只支持 long-polling Comet 服务器, 首先要具备解析 HTTP 协议的能力, 我选择 libevent 来处理 HTTP 协议.

    Continue reading »

    Posted by ideawu at 2013-09-18 22:06:31 Tags: , ,
  • 2013-09-17

    让libevent HTTP服务器立即知道客户端的断开

    Views: 32979 | No Comments

    虽然 libevent HTTP 服务器可以给连接注册关闭回调, 但客户端强制断开连接时, 服务器并没有立即知道.

     evhttp_connection_set_closecb(req->evcon, on_close, NULL);
    

    原来, libevent 在收到 HTTP 请求后, 就不再监听读事件了, 所以就不能通过 read() 返回 0 来知道连接断开, 只能通过 send() 导致 SIGPIPE 才能知道.

    为了让服务器立即知道客户端的断开, 只需要重新监听 EV_READ 事件即可.

    struct bufferevent *bev = evhttp_connection_get_bufferevent(req->evcon);
    bufferevent_enable(bev, EV_READ);
    
    Posted by ideawu at 2013-09-17 13:48:33 Tags:
  • 2013-09-11

    Libevent 2 HTTP 客户端示例

    Views: 32773 | No Comments

    Libevent 的文档非常少, 而且示例也很奇缺, 在 Google 里一搜, 还真找不到一两个. 这里贴一个最简单的利用 Libevent 2 HTTP 库, 作为客户端向服务器发起请求的例子.

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <unistd.h>
    #include <evhttp.h>
    #include <event2/event.h>
    #include <event2/http.h>
    #include <event2/bufferevent.h>
    
    void http_request_done(struct evhttp_request *req, void *arg){
        char buf[1024];
        int s = evbuffer_remove(req->input_buffer, &buf, sizeof(buf) - 1);
        buf[s] = '\0';
        printf("%s", buf);
        // terminate event_base_dispatch()
        event_base_loopbreak((struct event_base *)arg);
    }
    
    int main(int argc, char **argv){
        struct event_base *base;
        struct evhttp_connection *conn;
        struct evhttp_request *req;
    
        base = event_base_new();
        conn = evhttp_connection_base_new(base, NULL, "127.0.0.1", 8080);
        req = evhttp_request_new(http_request_done, base);
    
        evhttp_add_header(req->output_headers, "Host", "localhost");
        //evhttp_add_header(req->output_headers, "Connection", "close");
    
        evhttp_make_request(conn, req, EVHTTP_REQ_GET, "/index.php?id=1");
        evhttp_connection_set_timeout(req->evcon, 600);
        event_base_dispatch(base);
    
        return 0;
    }
    
    Posted by ideawu at 2013-09-11 21:53:02 Tags:
|<<<1>>>| 1/1 Pages, 4 Results.