跨平台的、具有异步能力的C/C++ HTTP库

24

我正在寻找一个能在Windows和Linux上使用的C/C++库,可以让我异步查询多个Web服务器(每分钟数千个),并以与WinHttp库在Windows环境中类似的方式下载网页标题和网页。

到目前为止,我发现libCurl似乎可以满足我的要求,但是异步方面看起来有些可疑。

您认为绕过使用库并从头开始编写基于套接字的简单程序以实现此目的有多容易?

欢迎任何评论、建议或建议。

补充说明:- 有关使用libCurl执行此操作的任何评论,我说异步方面可能会有问题,但是否有任何经验呢?


1
对于头部,您可以从头开始编写 - HTTP协议非常简单。内容下载部分会变得有些棘手 - 涉及到内容编码/压缩。 - Poni
@ Poni,感谢您的检查和指出内容下载困难。 - Rich
我也曾为一个网络爬虫做过类似的事情,但是没有找到令人满意的工具。我很快就放弃了使用libCurl,花了4周时间编写了我的专用Linux库来处理大规模下载。在现代Xeon机器上,保持50000个HTTP连接处于活动状态并占用10GBit连接是没有问题的。 - Lothar
3个回答

34

尝试使用libevent的HTTP例程。你可以创建一个HTTP连接并提供一个回调函数,在收到响应(或超时事件触发)时调用它。

更新: 我构建了一个分布式HTTP连接限流代理,并在同一个守护程序中使用了客户端和服务器部分,全部在单个线程上运行,效果很好。

如果你正在编写一个HTTP客户端,libevent 应该是很合适的选择。在服务端方面,唯一的限制是缺少配置选项--如果你想添加更高级功能,API 有点不够充足;不过这也是我预期的,因为它从来没有打算替换像Apache、Nginx这样的通用Web服务器。例如,我对其进行了补丁,以添加自定义子例程,限制入站HTTP请求的总大小(例如,在读取10MB后关闭连接)。代码非常精简易懂,补丁很容易实现。

我使用的是1.3.x分支;2.x分支相较于旧版有一些严重的性能改进

代码示例:花了几分钟写了一个快速示例,这应该能让你熟悉libevent的编程风格:

#include <stdio.h>
#include <event.h>
#include <evhttp.h>

void
_reqhandler(struct evhttp_request *req, void *state)
{
    printf("in _reqhandler. state == %s\n", (char *) state);
    if (req == NULL) {
        printf("timed out!\n");
    } else if (req->response_code == 0) {
        printf("connection refused!\n");
    } else if (req->response_code != 200) {
        printf("error: %u %s\n", req->response_code, req->response_code_line);
    } else {
        printf("success: %u %s\n", req->response_code, req->response_code_line);
    }
    event_loopexit(NULL);
}

int
main(int argc, char *argv[])
{
    const char *state = "misc. state you can pass as argument to your handler";
    const char *addr = "127.0.0.1";
    unsigned int port = 80;
    struct evhttp_connection *conn;
    struct evhttp_request *req;

    printf("initializing libevent subsystem..\n");
    event_init();

    conn = evhttp_connection_new(addr, port);
    evhttp_connection_set_timeout(conn, 5);
    req = evhttp_request_new(_reqhandler, (void *)state);
    evhttp_add_header(req->output_headers, "Host", addr);
    evhttp_add_header(req->output_headers, "Content-Length", "0");
    evhttp_make_request(conn, req, EVHTTP_REQ_GET, "/");

    printf("starting event loop..\n");
    event_dispatch();

    return 0;
}

编译并运行:

% gcc -o foo foo.c -levent
% ./foo    
initializing libevent subsystem..
starting event loop..
in _reqhandler. state == misc. state you can pass as argument to your handler
success: 200 OK

看了一下libevent的网站,感觉很有前途。你有使用过这个库的经验吗? - Rich
是的,我用过几次。我会更新答案并提供更多细节。 - samplebias
+1 for libevent,你也可以考虑使用libev。不过我的经验仅限于libevent。 - strkol

3

微软的cpprestsdk是一个跨平台的http库,可以与http服务器进行通信。在这里有一些msdn上的示例代码。它在Linux上使用boost asio,在Windows上使用WinHttp。


1
@tcp Boost Beast 有什么优势?它比其他的更好吗? - sorosh_sabz

0

尝试 https://github.com/ithewei/libhv

libhv是一个跨平台的轻量级网络库,用于开发TCP/UDP/SSL/HTTP/WebSocket客户端/服务器。

HTTP客户端示例:

    auto resp = requests::get("http://127.0.0.1:8080/ping");
    if (resp == NULL) {
        printf("request failed!\n");
    } else {
        printf("%d %s\r\n", resp->status_code, resp->status_message());
        printf("%s\n", resp->body.c_str());
    }

    hv::Json jroot;
    jroot["user"] = "admin";
    jroot["pswd"] = "123456";
    http_headers headers;
    headers["Content-Type"] = "application/json";
    resp = requests::post("127.0.0.1:8080/echo", jroot.dump(), headers);
    if (resp == NULL) {
        printf("request failed!\n");
    } else {
        printf("%d %s\r\n", resp->status_code, resp->status_message());
        printf("%s\n", resp->body.c_str());
    }

    // async
    int finished = 0;
    Request req(new HttpRequest);
    req->url = "http://127.0.0.1:8080/echo";
    req->method = HTTP_POST;
    req->body = "This is an async request.";
    req->timeout = 10;
    requests::async(req, [&finished](const HttpResponsePtr& resp) {
        if (resp == NULL) {
            printf("request failed!\n");
        } else {
            printf("%d %s\r\n", resp->status_code, resp->status_message());
            printf("%s\n", resp->body.c_str());
        }
        finished = 1;
    });

更多用法请参见https://github.com/ithewei/libhv/blob/master/examples/http_client_test.cpp


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接