Skip to content

Instantly share code, notes, and snippets.

@cuber
Created April 4, 2015 11:28
Show Gist options
  • Save cuber/c6abe29bcaa93ff539bf to your computer and use it in GitHub Desktop.
Save cuber/c6abe29bcaa93ff539bf to your computer and use it in GitHub Desktop.
Concurrent Http Client of Libevent
//
// 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