Libevent implements HTTP client

Source: Internet
Author: User

Libevent is used to implement an HTTP client.

I always wanted to find a client-side example based on libevent. I did not find a suitable one. When an HTTP request is sent, the other party does not respond. After studying the evhttp source code today, I suddenly found a stupid error: A blank line ("\ r \ n") was missing when I sent the request "). Ah, it's amazing.

In fact, I want to use the libevent event processing mechanism and share some functional modules on Linux and Android systems. I will first use httpclient for an experiment. Thanks for using http_parser to parse httpheader.

I tried it in a pure C environment. I implemented two secondary structs (using function pointers to simulate class implementations ). Struct c_string is used for string processing, and struct tag_value_list is used to store HTTP header field and header value. My experiment is familiar with libevent, and the code passes through.

Let's take a look at the main. C code, mainly how to use libevent.

#include "event2/event-config.h"#include "event2/event_compat.h"#include "event2/event.h"#include "event2/util.h"#include "event2/bufferevent.h"#include "event2/dns.h"#include "event2/buffer.h"#include "http_client.h"#ifndef WIN32#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h>#endif#include <string.h>void write_cb(evutil_socket_t sock, short flags, void * args){    struct http_client *httpc = (struct http_client *)args;     struct c_string * string = httpc->request_string(httpc);    int len = string->len(string);    int sent = 0;    int ret = 0;    printf("connected, write headers: %s\n", string->data);    ret = send(sock, string->data, len, 0);    while(ret != -1)    {        sent += ret;        if(sent == len) break;        ret = send(sock, string->data + sent, len - sent, 0);    }    delete_c_string(string);    event_add((struct event*)httpc->user_data[1], 0);}void read_cb(evutil_socket_t sock, short flags, void * args){    struct http_client *httpc = (struct http_client*)args;    int ret = recv(sock, httpc->parse_buffer, PARSE_BUFFER_SIZE, 0);        printf("read_cb, read %d bytes\n", ret);    if(ret > 0)    {        httpc->process_data(httpc, httpc->parse_buffer, ret);    }    else if(ret == 0)    {        printf("read_cb connection closed\n");        event_base_loopexit((struct event_base*)httpc->user_data[0], NULL);        return;    }    if(httpc->finished(httpc) != 0)    {        event_add((struct event*)httpc->user_data[1], 0);    }}static evutil_socket_t make_tcp_socket(){    int on = 1;    evutil_socket_t sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    evutil_make_socket_nonblocking(sock);#ifdef WIN32    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char *)&on, sizeof(on));#else    setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));#endif    return sock;}static struct http_client * make_http_client(struct event_base * base, const char *url){    struct http_client * httpc = new_http_client();    /* initialize http client */    httpc->user_data[0] = base;    if(0 == httpc->parse_url(httpc, url) )    {        httpc->add_request_header(httpc, "Accept", "*/*");        httpc->add_request_header(httpc, "User-Agent", "test http client");        return httpc;    }    delete_http_client(httpc);    printf("parse url failed\n");    return 0;}int download(struct event_base * base, const char *url){    evutil_socket_t sock = make_tcp_socket();    struct sockaddr_in serverAddr;    struct http_client * httpc = make_http_client(base, url);    struct event * ev_write = 0;    struct event * ev_read = 0;    struct timeval tv={10, 0};    if(!httpc) return -1;    serverAddr.sin_family = AF_INET;    serverAddr.sin_port = htons(httpc->port);#ifdef WIN32    serverAddr.sin_addr.S_un.S_addr = inet_addr(httpc->host);#else    serverAddr.sin_addr.s_addr = inet_addr(httpc->host);#endif    memset(serverAddr.sin_zero, 0x00, 8);    connect(sock, (struct sockaddr*)&serverAddr, sizeof(serverAddr));    ev_write = event_new(base, sock, EV_WRITE, write_cb, (void*)httpc);    ev_read = event_new(base, sock, EV_READ , read_cb, (void*)httpc);    httpc->user_data[1] = ev_read;    event_add(ev_write, &tv);    return 0;}int main(int argc, char** argv){    struct event_base * base = 0;#ifdef WIN32    WORD wVersionRequested;    WSADATA wsaData;    wVersionRequested = MAKEWORD(2, 2);    (void) WSAStartup(wVersionRequested, &wsaData);#endif    if(argc < 2)    {        printf("usage: %s http://111.222.333.44:8080/xxx.htm\n    now only support ip.\n", argv[0]);        return 1;    }    base = event_base_new();    if( 0 == download(base, argv[1]) )    {        event_base_dispatch(base);        event_base_free(base);    }    else    {        printf("prepare download failed for %s\n", argv[1]);    }    return 0;}

The example is relatively simple. You can use the command line to upload parameters and download resources represented by a specified URL, the downloaded resources are not processed either. (You can add a data processing callback interface to the struct http_client to process the data ). Currently, it can run on Windows and cent OS.

The program is not rigorous, some errors are not handled, and some memory is not released. Only demonstrate how to use libevent to implement the client program. Perform the following steps:

  1. Initialize event_base (subsequent event loops)
  2. Create a socket, set it to asynchronous, and connect to the server
  3. Create a write read/write event. Add the write event to the event loop first.
  4. Send a request to the server in the write Event Callback and add the read event to the event loop.
  5. Process data in the read Event Callback and determine whether to add read events based on whether the data is read.

The details of the Protocol can be freely implemented based on the Program purpose.

I didn't use bufferevent. There are many examples on the Internet and I will not mention them here. Next, I want to test UDP to see if it is successful.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.