Created
April 4, 2015 11:28
-
-
Save cuber/c6abe29bcaa93ff539bf to your computer and use it in GitHub Desktop.
Concurrent Http Client of Libevent
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// evhttp_client.cc | |
// | |
// Created by Cube on 15/4/3. | |
// Copyright (c) 2015年 Cube. All rights reserved. | |
// | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <event2/dns.h> | |
#include <event2/http.h> | |
#include <event2/http_struct.h> | |
#include <event2/event.h> | |
struct dns_t; | |
struct con_t; | |
struct clo_t { | |
event * e; | |
evhttp_connection * con; | |
timeval tv; | |
}; | |
struct req_t { | |
evhttp_request * req; | |
dns_t * dns; | |
con_t * con; | |
int c; | |
}; | |
struct con_t { | |
event * e; | |
evhttp_connection * con; | |
req_t * r; | |
dns_t * dns; | |
timeval tv, tvc; | |
int p,c; | |
}; | |
struct dns_t { | |
event * e; | |
event_base * eb; | |
evdns_base * ev_dns; | |
evutil_addrinfo * ev_hit; | |
timeval tv; | |
char ip[32]; | |
const char * host; | |
con_t * c; | |
int p; | |
dns_t() { | |
// init hints | |
ev_hit = (evutil_addrinfo *)calloc(1, sizeof(evutil_addrinfo)); | |
ev_hit->ai_family = AF_UNSPEC; | |
ev_hit->ai_flags = EVUTIL_AI_CANONNAME; | |
/** | |
* Unless we specify a socktype, we'll get at least two entries for | |
* each address: one for TCP and one for UDP. That's not what we | |
* want. | |
*/ | |
ev_hit->ai_socktype = SOCK_STREAM; | |
ev_hit->ai_protocol = IPPROTO_TCP; | |
} | |
}; | |
static void evo_cb(int, short, void * ptr) | |
{ | |
clo_t * clo = (clo_t *)ptr; | |
printf("%p close\n", clo->con); | |
event_free(clo->e); | |
evhttp_connection_free(clo->con); | |
} | |
static void req_cb(evhttp_request * req, void * ptr) | |
{ | |
req_t * r = (req_t *)ptr; | |
printf("con(%02d): %p req(%02d) -> %p %d\n", r->con->c + 1, r->con->con, r->c + 1, req, req ? req->response_code : -1); | |
r->dns->p--; | |
r->con->p--; | |
if (r->con->p) return; | |
clo_t * clo = (clo_t *)calloc(1, sizeof(clo_t)); | |
clo->con = r->con->con; | |
clo->e = evtimer_new(r->dns->eb, evo_cb, clo); | |
evtimer_add(clo->e, &clo->tv); | |
} | |
static void evc_cb(int, short, void * ptr) | |
{ | |
con_t * c = (con_t *)ptr; | |
if ( c->p) { | |
return; | |
return (void)printf("%s is processing\n", __FUNCTION__); | |
} | |
if (!c->r) c->r = (req_t *)calloc(10, sizeof(req_t)); | |
// make connection | |
c->con = evhttp_connection_base_new(c->dns->eb, NULL, c->dns->ip, 80); | |
// traverse | |
for (int i = 0; i < 10; i++) | |
{ | |
c->p++; | |
req_t * r = c->r + i; | |
r->c = i; | |
r->con = c; | |
r->dns = c->dns; | |
r->req = evhttp_request_new(req_cb, r); | |
evhttp_add_header(r->req->output_headers, "Host", r->dns->host); | |
evhttp_make_request(c->con, r->req, EVHTTP_REQ_GET, "/"); | |
} | |
// after all request done, free the connection | |
// the beta version has this function | |
// evhttp_connection_free_on_completion(c->con); | |
} | |
static void req_do(char ip[32], dns_t * dns) | |
{ | |
// copy | |
memcpy(dns->ip, ip, 32); | |
// malloc req | |
if (dns->p) { | |
return; | |
return (void)printf("%s is processing\n", __FUNCTION__); | |
} | |
if (dns->c) return; | |
// malloc con | |
dns->c = (con_t *)calloc(5, sizeof(con_t)); | |
// traverse | |
for (int i = 0; i < 5; i++) | |
{ | |
dns->p += 50; | |
con_t * c = dns->c + i; | |
c->dns = dns; | |
c->c = i; | |
c->tv.tv_sec = 5; | |
c->e = event_new(dns->eb, -1, EV_TIMEOUT | EV_PERSIST, evc_cb, c); | |
event_add(c->e, &c->tv); | |
} | |
} | |
static void dns_cb(int err, struct addrinfo * addr, void * ptr) | |
{ | |
dns_t * dns = (dns_t *)ptr; | |
for (evutil_addrinfo * ai = addr; ai; ai = ai->ai_next) | |
{ | |
const char * s = NULL; char ip[32]; | |
if (ai->ai_family != AF_INET) continue; | |
struct sockaddr_in * sin = (struct sockaddr_in *)ai->ai_addr; | |
s = evutil_inet_ntop(AF_INET, &sin->sin_addr, ip, 32); | |
if (s) return req_do(ip, dns); | |
} | |
if (addr) evutil_freeaddrinfo(addr); | |
} | |
static void evt_cb(int, short, void * ptr) | |
{ | |
dns_t * dns = (dns_t *)ptr; | |
dns->host = "localhost"; | |
// process | |
evdns_getaddrinfo(dns->ev_dns, dns->host, NULL, dns->ev_hit, dns_cb, dns); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
dns_t * dns = new dns_t; | |
dns->eb = event_base_new(); | |
dns->e = event_new(dns->eb, -1, EV_TIMEOUT | EV_PERSIST, evt_cb, dns); | |
dns->ev_dns = evdns_base_new(dns->eb, 1); | |
dns->tv.tv_sec = 1; | |
event_add(dns->e, &dns->tv); | |
event_base_loop(dns->eb, 0); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment