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);
}