libevent http client 구현

libevent 를 사용 하여 http client 를 실현 하 였 습 니 다.
제 결승전 글 인'Qt Quick 이미지 처리 인 스 턴 스 의 미 투 쇼(원본 다운로드)'에 투표 해 주 십시오.감사합니다.
libevent 를 기반 으로 한 client 엔 드 의 예 를 찾 고 싶 었 지만 적당 한 것 을 찾 지 못 하고 스스로 만 들 었 습 니 다.질문 이 있 으 면 http 요청 을 하면 상대방 은 항상 반응 이 없습니다.오늘 evhttp 소스 코드 를 연구 하 다가 갑자기 어 리 석 은 오류 가 발견 되 었 습 니 다.요청 을 보 낼 때 빈 줄 이 하나 빠 졌 습 니 다("\r").아,재주 가 대단 하군.
사실은 libevent 의 이벤트 처리 체 제 를 이용 하여 Liux 와 안 드 로 이 드 두 시스템 에서 일부 기능 모듈 을 공유 하려 면 먼저 httpclient 를 가지 고 시험 을 해 보 려 고 합 니 다.http 사용parser 에서 httpheader 를 해석 해 주 셔 서 감사합니다.
순수 C 의 환경 에서 시험 한 것 으로 나 는 두 개의 보조 구조 체(함수 포인터 모방 류 의 실현)를 실현 했다.struct c_string 문자열 처리 에 사용,struct tagvalue_list 는 http header field 와 header value 를 저장 하 는 데 사 용 됩 니 다.나의 실험 은 libevent 를 잘 알 고 있 는데,이 코드 들 이 스 쳐 지나 갔다.
main.c 의 코드 를 살 펴 보 겠 습 니 다.주로 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
", 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
", ret); if(ret > 0) { httpc->process_data(httpc, httpc->parse_buffer, ret); } else if(ret == 0) { printf("read_cb connection closed
"); 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
"); 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
now only support ip.
", 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
", argv[1]); } return 0; }

예 는 간단 합 니 다.명령 행 을 통 해 지정 한 URL 대표 자원 을 다운로드 하고 다운로드 한 자원 도 처리 되 지 않 았 습 니 다.(추 후 struct http 에 게 전달 할 수 있 습 니 다.client 데이터 처리 인 터 페 이 스 를 추가 하여 데 이 터 를 처리 합 니 다).현재 windows 와 cent os 에서 실행 할 수 있 습 니 다.
프로그램 이 엄밀 하지 않 고 일부 오류 가 처리 되 지 않 았 으 며 일부 메모리 가 풀 리 지 않 았 습 니 다.libevent 를 사용 하여 client 프로그램 을 실현 하 는 방법 만 보 여 줍 니 다.대략 다음 절 차 를 거치 면 된다.
  • event 초기 화base(후속 실행 이벤트 순환)
  • socket 을 만 들 고 비동기 로 설정 하 며 server
  • 를 연결 합 니 다.
  • 쓰기 읽 기 쓰기 이 벤트 를 만 들 고 쓰기 이 벤트 를 이벤트 순환 에 추가 합 니 다
  • 이벤트 리 셋 에서 서버 에 요청 을 보 내 고 읽 기 이 벤트 를 이벤트 순환 에 추가 합 니 다
  • 읽 기 이벤트 리 셋 에서 데 이 터 를 처리 하고 데이터 읽 기 완료 여부 에 따라 읽 기 이벤트 추가 여 부 를 결정 합 니 다
  • 협의의 처리 세부 사항 은 절차 목적 에 따라 자 유 롭 게 실현 할 수 있다.
    저 는 bufferevent 를 사용 하지 않 았 습 니 다.인터넷 에 많은 예 가 있 습 니 다.더 이상 언급 하지 않 겠 습 니 다.다음은 성공 할 수 있 는 지 UDP 를 시험 해 보고 싶 습 니 다.

    좋은 웹페이지 즐겨찾기