libevent evhttp学习——http客户端
基本環(huán)境
使用版本為libevent-2.1.5,目前為beta版,其中evhttp和舊版區(qū)別在于新增了如下接口
// 設(shè)置回調(diào)函數(shù),在包頭讀取完成后回調(diào) void evhttp_request_set_header_cb (struct evhttp_request *, int(*cb)(struct evhttp_request *, void *))// 設(shè)置回調(diào)函數(shù),在body有數(shù)據(jù)返回后回調(diào) void evhttp_request_set_chunked_cb (struct evhttp_request *, void(*cb)(struct evhttp_request *, void *))- 1
- 2
- 3
- 4
- 5
這樣的好處是可以在合適的時(shí)機(jī)回調(diào)我們注冊(cè)的回調(diào)函數(shù),比如下載1G的文件,在之前的版本只有下載完成后才會(huì)回調(diào),現(xiàn)在每下載一部分?jǐn)?shù)據(jù)就會(huì)回調(diào)一次,讓上層應(yīng)用更加靈活,尤其在http代理時(shí),可以做到邊下載邊回復(fù)
2.1.5版本的完整接口文檔詳見http://www.wangafu.net/~nickm/libevent-2.1/doxygen/html/http_8h.html
請(qǐng)求流程
http客戶端使用到的接口函數(shù)及請(qǐng)求流程如下
初始化event_base和evdns_base
struct event_base *event_base_new(void); struct evdns_base * evdns_base_new(struct event_base *event_base, int initialize_nameservers);- 1
- 2
創(chuàng)建evhttp_request對(duì)象,并設(shè)置回調(diào)函數(shù),這里的回調(diào)函數(shù)是和數(shù)據(jù)接收相關(guān)的
struct evhttp_request *evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg); void evhttp_request_set_header_cb(struct evhttp_request *, int (*cb)(struct evhttp_request *, void *)); void evhttp_request_set_chunked_cb(struct evhttp_request *, void (*cb)(struct evhttp_request *, void *)); void evhttp_request_set_error_cb(struct evhttp_request *, void (*)(enum evhttp_request_error, void *));- 1
- 2
- 3
- 4
創(chuàng)建evhttp_connection對(duì)象,并設(shè)置回調(diào)函數(shù),這里的回調(diào)函數(shù)是和連接狀態(tài)相關(guān)的
struct evhttp_connection *evhttp_connection_base_new(struct event_base *base, struct evdns_base *dnsbase, const char *address, unsigned short port); void evhttp_connection_set_closecb(struct evhttp_connection *evcon,void (*)(struct evhttp_connection *, void *), void *);- 1
- 2
- 3
- 4
有選擇的向evhttp_request添加包頭字段
int evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value);- 1
發(fā)送請(qǐng)求
int evhttp_make_request(struct evhttp_connection *evcon,struct evhttp_request *req,enum evhttp_cmd_type type, const char *uri);- 1
- 2
- 3
派發(fā)事件
int event_base_dispatch(struct event_base *);完整代碼
#include "event2/http.h" #include "event2/http_struct.h" #include "event2/event.h" #include "event2/buffer.h" #include "event2/dns.h" #include "event2/thread.h"#include <stdio.h> #include <string.h> #include <assert.h> #include <sys/queue.h> #include <event.h>void RemoteReadCallback(struct evhttp_request* remote_rsp, void* arg) {event_base_loopexit((struct event_base*)arg, NULL); } int ReadHeaderDoneCallback(struct evhttp_request* remote_rsp, void* arg) {fprintf(stderr, "< HTTP/1.1 %d %s\n", evhttp_request_get_response_code(remote_rsp), evhttp_request_get_response_code_line(remote_rsp));struct evkeyvalq* headers = evhttp_request_get_input_headers(remote_rsp);struct evkeyval* header;TAILQ_FOREACH(header, headers, next){fprintf(stderr, "< %s: %s\n", header->key, header->value);}fprintf(stderr, "< \n");return 0; }void ReadChunkCallback(struct evhttp_request* remote_rsp, void* arg) {char buf[4096];struct evbuffer* evbuf = evhttp_request_get_input_buffer(remote_rsp);int n = 0;while ((n = evbuffer_remove(evbuf, buf, 4096)) > 0){fwrite(buf, n, 1, stdout);} }void RemoteRequestErrorCallback(enum evhttp_request_error error, void* arg) {fprintf(stderr, "request failed\n");event_base_loopexit((struct event_base*)arg, NULL); }void RemoteConnectionCloseCallback(struct evhttp_connection* connection, void* arg) {fprintf(stderr, "remote connection closed\n");event_base_loopexit((struct event_base*)arg, NULL); }int main(int argc, char** argv) {if (argc != 2){printf("usage:%s url", argv[1]);return 1;}char* url = argv[1];struct evhttp_uri* uri = evhttp_uri_parse(url);if (!uri){fprintf(stderr, "parse url failed!\n");return 1;}struct event_base* base = event_base_new();if (!base){fprintf(stderr, "create event base failed!\n");return 1;}struct evdns_base* dnsbase = evdns_base_new(base, 1);if (!dnsbase){fprintf(stderr, "create dns base failed!\n");}assert(dnsbase);struct evhttp_request* request = evhttp_request_new(RemoteReadCallback, base);evhttp_request_set_header_cb(request, ReadHeaderDoneCallback);evhttp_request_set_chunked_cb(request, ReadChunkCallback);evhttp_request_set_error_cb(request, RemoteRequestErrorCallback);const char* host = evhttp_uri_get_host(uri);if (!host){fprintf(stderr, "parse host failed!\n");return 1;}int port = evhttp_uri_get_port(uri);if (port < 0) port = 80;const char* request_url = url;const char* path = evhttp_uri_get_path(uri);if (path == NULL || strlen(path) == 0){request_url = "/";}printf("url:%s host:%s port:%d path:%s request_url:%s\n", url, host, port, path, request_url);struct evhttp_connection* connection = evhttp_connection_base_new(base, dnsbase, host, port);if (!connection){fprintf(stderr, "create evhttp connection failed!\n");return 1;}evhttp_connection_set_closecb(connection, RemoteConnectionCloseCallback, base);evhttp_add_header(evhttp_request_get_output_headers(request), "Host", host);evhttp_make_request(connection, request, EVHTTP_REQ_GET, request_url);event_base_dispatch(base);return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
編譯
g++ http_client.cpp -I/opt/local/libevent-2.1.5/include -L/opt/local/libevent-2.1.5/lib -levent -g -o http_client運(yùn)行示例,這里只打印了包頭字段
$ ./http_client http://www.qq.com >/dev/null < HTTP/1.1 200 OK < Server: squid/3.4.3 < Content-Type: text/html; charset=GB2312 < Cache-Control: max-age=60 < Expires: Fri, 05 Aug 2016 08:48:31 GMT < Date: Fri, 05 Aug 2016 08:47:31 GMT < Transfer-Encoding: chunked < Connection: keep-alive < Connection: Transfer-Encoding <總結(jié)
以上是生活随笔為你收集整理的libevent evhttp学习——http客户端的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux系统编程10:进程入门之系统编
- 下一篇: 【.NET】Repeater控件简单的数