libevent通常作为服务端,但是有场景会作为客户端去抓取别的服务,通常可以使用libcurl去抓取,但是会使整个线程处于等待状态,这时可以使用libevent客户端模式,使请求完全异步。
#ifndef _EVENT_CURL_H_ #define _EVENT_CURL_H_ #include <string> using namespace std; typedef void (*RequestFinishHandler)(struct evhttp_request *req, void *arg); struct event_base; class EventHttpReq { public: EventHttpReq() { m_time_out = 300; finish_handler = NULL; finish_arg = NULL; } string m_url; string m_post_data; int m_time_out; RequestFinishHandler finish_handler; void *finish_arg; }; class EventCurl { public: static bool curl(EventHttpReq &eventHttpReq, struct event_base *, struct evhttp_connection *& conn); }; #endif
#include <signal.h> #include <sys/socket.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <arpa/inet.h> #include <netinet/tcp.h> #include "EventCurl.h" #include "event2/util.h" #include "event2/http.h" #include "event2/http_struct.h" #include "event2/buffer.h" bool EventCurl::curl(EventHttpReq &eventHttpReq, struct event_base *base, struct evhttp_connection *& conn) { struct evhttp_request *req; const char *scheme, *host, *path, *query; struct evhttp_uri *http_uri = evhttp_uri_parse(eventHttpReq.m_url.c_str()); if (NULL == http_uri) { return false; } string uri; int port; scheme = evhttp_uri_get_scheme(http_uri); if (scheme == NULL || (strcasecmp(scheme, "https") != 0 && strcasecmp(scheme, "http") != 0)) { evhttp_uri_free(http_uri); return false; } host = evhttp_uri_get_host(http_uri); if (NULL == host) { evhttp_uri_free(http_uri); return false; } port = evhttp_uri_get_port(http_uri); if (port == -1) { port = (strcasecmp(scheme, "http") == 0) ? 80 : 443; } path = evhttp_uri_get_path(http_uri); if (path == NULL || strlen(path) == 0) { uri = "/"; } else { uri = path; } query = evhttp_uri_get_query(http_uri); if (query != NULL) { uri += "?"; uri += query; } conn = evhttp_connection_base_new(base, NULL, host, port); if (NULL == conn) { evhttp_uri_free(http_uri); return false; } req = evhttp_request_new(eventHttpReq.finish_handler, eventHttpReq.finish_arg); if (NULL == req) { evhttp_connection_free(conn); evhttp_uri_free(http_uri); conn = NULL; return false; } evhttp_add_header(req->output_headers, "Host", host); int make_request_ret = 0; if (eventHttpReq.m_post_data.size() > 0) //post请求,则加入post的内容 { evbuffer_add(req->output_buffer, eventHttpReq.m_post_data.c_str(), eventHttpReq.m_post_data.size()); make_request_ret = evhttp_make_request(conn, req, EVHTTP_REQ_POST, uri.c_str()); } else //get请求 { make_request_ret = evhttp_make_request(conn, req, EVHTTP_REQ_GET, uri.c_str()); } if (make_request_ret != 0) { evhttp_connection_free(conn); evhttp_request_free(req); evhttp_uri_free(http_uri); conn = NULL; return false; } evhttp_connection_set_timeout(req->evcon, eventHttpReq.m_time_out); evhttp_uri_free(http_uri); return true; }
收到返回结果,或异常时的处理。
void finish_handler(struct evhttp_request *req, void *arg) { EParser *parser = (EParser *)arg; parser->m_curl_time = parser->m_timer.ElapseTime(); int http_code = 0; if (req != NULL) { http_code = evhttp_request_get_response_code(req); //http码 parser->m_http_code = http_code; if (http_code == HTTP_OK) { int s = evbuffer_remove(req->input_buffer, &parser->curl_result, E_MAX_SIZE_BUF); struct evkeyvalq* headers = evhttp_request_get_input_headers(req); //http头部 for (evkeyval* header = headers->tqh_first; header != NULL; header = header->next.tqe_next) { parser->m_receive_header.insert(std::pair<string, string>(header->key, header->value)); } } } parser->m_is_finish = true; ProcessRequestSend(EParser); }