`
king_tt
  • 浏览: 2115707 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

libevent http client

 
阅读更多

我自己在实现一个http client,使用libevent,遇到一些问题,连接可以建立,但发送http请求后毫无反应。实验了windows和linux两个版本,都是如此。可能还是我使用上的问题。

请给我的决赛文章Qt Quick 图像处理实例之美图秀秀(附源码下载)投票,谢谢。

根据网上的例子修改了一下,可以在windows下面跑,没问题了。代码如下:

#include <stdlib.h>
#include <string.h>
#include "event2/event.h"
#include "event2/http.h"
#include "event2/buffer.h"
#include "event2/http_struct.h"
#include "event2/dns.h"


struct download_context{
    struct evhttp_uri * uri;
    struct event_base * base;
    struct evdns_base * dnsbase;
    struct evhttp_connection * conn;
    struct evhttp_request *req;
    struct evbuffer *buffer;
    int ok;
};

static void download_callback(struct evhttp_request *req, void *arg);
static int download_renew_request(struct download_context *ctx);

static void download_callback(struct evhttp_request *req, void *arg)
{
    struct download_context * ctx = (struct download_context*)arg;
    struct evhttp_uri * new_uri = 0;
    const char * new_location = 0;
    if(!req){
        printf("timeout\n");
        return;
    }

    switch(req->response_code)
    {
    case HTTP_OK:
        event_base_loopexit(ctx->base, 0);
        break;
    case HTTP_MOVEPERM:
    case HTTP_MOVETEMP:
        new_location = evhttp_find_header(req->input_headers, "Location");
        if(!new_location) return;
        new_uri = evhttp_uri_parse(new_location);
        if(!new_uri)return;
        evhttp_uri_free(ctx->uri);
        ctx->uri = new_uri;
        download_renew_request(ctx);
        return;
    default:/* failed */
        event_base_loopexit(ctx->base, 0);
        return;
    }

    evbuffer_add_buffer(ctx->buffer, req->input_buffer);
    ctx->ok = 1;
}

struct download_context * context_new(const char *url)
{
    struct download_context * ctx = 0;
    ctx = (struct download_context*)calloc(1, sizeof(struct download_context));
    ctx->uri = evhttp_uri_parse(url);
    if(!ctx->uri) return 0;

    ctx->base = event_base_new();
    ctx->buffer = evbuffer_new();
    ctx->dnsbase = evdns_base_new(ctx->base, 1);

    download_renew_request(ctx);
    return ctx;
}

void context_free(struct download_context *ctx)
{
    if(ctx->conn)
        evhttp_connection_free(ctx->conn);

    if(ctx->buffer)
        evbuffer_free(ctx->buffer);

    if(ctx->uri)
        evhttp_uri_free(ctx->uri);

    free(ctx);
}

static int download_renew_request(struct download_context *ctx)
{
    int port = evhttp_uri_get_port(ctx->uri);
    if(port == -1) port = 80;
    if(ctx->conn) evhttp_connection_free(ctx->conn);

    printf("host:%s, port:%d, path:%s\n", evhttp_uri_get_host(ctx->uri), port, evhttp_uri_get_path(ctx->uri));

    ctx->conn = evhttp_connection_base_new(ctx->base, ctx->dnsbase, evhttp_uri_get_host(ctx->uri),  port );
    ctx->req = evhttp_request_new(download_callback, ctx);
    evhttp_make_request(ctx->conn, ctx->req, EVHTTP_REQ_GET, evhttp_uri_get_path(ctx->uri));
    evhttp_add_header(ctx->req->output_headers, "Host", evhttp_uri_get_host(ctx->uri));

    return 0;
}

struct evbuffer *download_url(const char *url)
{
    struct download_context * ctx = context_new(url);
    if(!ctx) return 0;

    event_base_dispatch(ctx->base);

    struct evbuffer * retval = 0;
    if(ctx->ok)
    {
        retval = ctx->buffer;
        ctx->buffer = 0;
    }

    context_free(ctx);
    return retval;
}

int main(int argc, char **argv)
{
    struct evbuffer * data = 0;
    if(argc < 2){
        printf("usage: %s example.com/\n", argv[0]);
        return 1;
    }

#ifdef WIN32
	WORD wVersionRequested;
	WSADATA wsaData;

	wVersionRequested = MAKEWORD(2, 2);

	(void) WSAStartup(wVersionRequested, &wsaData);
#endif

    data = download_url(argv[1]);

    printf("got %d bytes\n", data ? evbuffer_get_length(data) : -1);

    if(data)
    {
        const unsigned char * joined = evbuffer_pullup(data, -1);
        printf("data itself:\n====================\n");
        fwrite(joined, evbuffer_get_length(data), 1, stderr);
        printf("\n====================\n");
        evbuffer_free(data);
    }

    return 0;
}

需要注意的是,如果从命令行传入网址,比如百度的,必须传入http://www.baidu.com/,否则解析不出来path,下载会失败。

这个例子不是我最终想要的效果,无法控制下载和数据处理过程,它是等下载完成了一次性返回数据。对于大文件,比如几百兆甚至上G的,这种处理策略还不够。我写了一个http处理的模块和一些辅助代码,编译通过,可以运行,但请求发出后对端始终无反应。等我查一查,网上始终找不到libevent http client的例子,有echoserver之类的,就是没有客户端。

研究研究吧,可能是事件的使用上有问题。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics