前面的文章《
Libcurl编译指南——Android和Windows系统
》已经就libcurl在Windows和Android系统编做了详细的说明。
本文档用C/C++实现简单的HTTP/HTTPS客户端,支持get和post,支持保持session和长连接。
#ifndef __HTTP_CONN_H__ #define __HTTP_CONN_H__ #include "curl.h" #define RETRY_TIMES 3 struct MemoryStruct { char *memory; unsigned int size; class RequestHandler private: public: MemoryBlock request; MemoryBlock response; int http_code; class HttpRequest private: CURL *curl_handle; CURLcode curl_res; long http_code; struct MemoryStruct receive_header; struct MemoryStruct receive_content; struct MemoryStruct error_message; struct curl_slist *http_headers; int retry_times; public: HttpRequest(); ~HttpRequest(); int setRequestUrl(const char *url); // 设置URL int setRequestHeader(const char *header); // 设置Header int setRequestTimeout(long time); // 设置超时时间 int setPostData(const char *data, unsigned int size); // 设置post数据 int setResultCallback(); // 回调 int performRequest(); // 发送数据 int sendReceiveEx(const char *url, RequestHandler *handler); // 发送和接收url请求 int getHttpCode(); //返回http code int getHeader(char *header, unsigned int *len); // 返回Header int getContent(char *content, unsigned int *len); #endif
httpConn.cpp
#include "httpConn.h" #include "curl.h" static unsigned int RetriveContentCallback(void *contents, unsigned int size, unsigned int nmemb, void *userp) unsigned int realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; char *ptr = (char*)realloc((void *)mem->memory, mem->size + realsize + 1); if (ptr == NULL) { /* out of memory! */ printf("not enough memory (realloc returned NULL)\n"); return -6; mem->memory = ptr; memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; static unsigned int RetriveHeaderCallback(void *contents, unsigned int size, unsigned int nmemb, void *userp) unsigned int realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *)userp; char *ptr = (char*)realloc((void *)mem->memory, mem->size + realsize + 1); if (ptr == NULL) { /* out of memory! */ printf("not enough memory (realloc returned NULL)\n"); return -6; mem->memory = ptr; memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; HttpRequest::HttpRequest() curl_res = CURLE_OK; http_code = 0; curl_handle = NULL; http_headers = NULL; retry_times = RETRY_TIMES; /* will be grown as needed by the realloc above */ receive_content.memory = (char*)malloc(1); receive_header.memory = (char*)malloc(1); error_message.memory = (char*)malloc(1); /* no data at this point */ receive_content.size = 0; receive_header.size = 0; /* global libcurl initialisation */ curl_global_init(CURL_GLOBAL_ALL); /* init the curl session */ curl_handle = curl_easy_init(); HttpRequest::~HttpRequest() /* cleanup curl stuff */ if (curl_handle) curl_easy_cleanup(curl_handle); free(receive_content.memory); free(receive_header.memory); free(error_message.memory); if (http_headers) curl_slist_free_all(http_headers); /* we're done with libcurl, so clean it up */ curl_global_cleanup(); int HttpRequest::setRequestUrl(const char *url) if (0 == memcmp(url, "https", 5)) curl_res = curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_SSL_VERIFYPEER failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_SSL_VERIFYHOST failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; #ifdef USE_PROXY curl_res = curl_easy_setopt(curl_handle, CURLOPT_PROXY, PROXY_ADDRESS); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_PROXY failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; #endif // USE_PROXY curl_res = curl_easy_setopt(curl_handle, CURLOPT_URL, url); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_URL failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; return 0; int HttpRequest::setRequestHeader(const char * header) http_headers = curl_slist_append(http_headers, header); curl_res = http_headers ? CURLE_OK : CURLE_FAILED_INIT; if (CURLE_OK != curl_res) printf("Set request header: curl_slist_append failed."); return -2; return 0; int HttpRequest::setRequestTimeout(long time) curl_res = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, time); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_TIMEOUT failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; return 0; int HttpRequest::setPostData(const char *data, unsigned int size) curl_res = curl_easy_setopt(curl_handle, CURLOPT_POST, 1); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_POST failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, data); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_POSTFIELDS failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, size); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_POSTFIELDSIZE failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; return 0; int HttpRequest::setResultCallback() /* send all data to this function */ curl_res = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, RetriveContentCallback); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_WRITEFUNCTION failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; /* we pass our 'receive_content' struct to the callback function */ curl_res = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&receive_content); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_WRITEDATA failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; /*curl_res = curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, RetriveHeaderCallback); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_HEADERFUNCTION failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)&receive_header); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_HEADERDATA failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; return 0; int HttpRequest::performRequest() if (curl_handle) setResultCallback(); setRequestTimeout(10); if (http_headers) curl_res = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, http_headers); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_HTTPHEADER failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; /* some servers don't like requests that are made without a user-agent field, so we provide one */ curl_res = curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_USERAGENT failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_NOPROGRESS failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_NOSIGNAL failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, 0); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_CONNECTTIMEOUT_MS failed. curl_res = %d, curl_strerror = %s", curl_res, curl_easy_strerror(curl_res)); return -1; /* get it! */ curl_res = curl_easy_perform(curl_handle); if (curl_res == CURLE_OPERATION_TIMEDOUT) int retry_count = retry_times; while (retry_count > 0) curl_res = curl_easy_perform(curl_handle); if (curl_res != CURLE_OPERATION_TIMEDOUT) break; retry_count--; if (curl_res == CURLE_OPERATION_TIMEDOUT) printf("curl_easy_perform failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -3; curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_code); if (curl_res != CURLE_OK || http_code != 200) printf("curl_easy_perform failed. curl_res = %d, Httpcode = %ld, curl_strerror = %s\n", curl_res, http_code, curl_easy_strerror(curl_res)); return -4; * Now, our receive_content.memory points to a memory block that is receive_content.size * bytes big and contains the remote file. * Do something nice with it! return 0; int HttpRequest::sendReceiveEx(const char * url, RequestHandler * handler) int ret = 0; int httpCpde = 0; char receive[20480] = { 0 }; unsigned int rlen = sizeof(receive); char requet[10240] = { 0 }; if (0 != handler->request.getSize()) sprintf(requet, "%s?%s#", url, handler->request.getData()); sprintf(requet, "%s", url); if (receive_content.memory) free(receive_content.memory); receive_content.memory = NULL; receive_content.memory = (char*)malloc(1); receive_content.size = 0; if (curl_handle) // set params curl_easy_reset(curl_handle); /* enable TCP keep-alive for this transfer */ curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPALIVE, 1L); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_TCP_KEEPALIVE failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; /* keep-alive idle time to 120 seconds */ curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPIDLE, 120L); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_TCP_KEEPIDLE failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; /* interval time between keep-alive probes: 30 seconds */ curl_easy_setopt(curl_handle, CURLOPT_TCP_KEEPINTVL, 30L); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_TCP_KEEPINTVL failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; /* export cookies to this file when closing the handle */ curl_easy_setopt(curl_handle, CURLOPT_COOKIEJAR, "./cookies.txt"); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_COOKIEJAR failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; /* get cookies from an existing file */ curl_easy_setopt(curl_handle, CURLOPT_COOKIEFILE, "./cookies.txt"); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_COOKIEFILE failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; setResultCallback(); setRequestTimeout(10); ret = setRequestUrl(url); if (0 != ret) return ret; setPostData((const char *)handler->request.getData(), handler->request.getSize()); if (http_headers) curl_res = curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, http_headers); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_HTTPHEADER failed. curl_res = %d, curl_strerror = %s", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_NOPROGRESS failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_NOSIGNAL failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; curl_res = curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT_MS, 0); if (CURLE_OK != curl_res) printf("curl_easy_setopt CURLOPT_CONNECTTIMEOUT_MS failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); return -1; /* get it! */ curl_res = curl_easy_perform(curl_handle); if (curl_res == CURLE_OPERATION_TIMEDOUT) int retry_count = retry_times; while (retry_count > 0) curl_res = curl_easy_perform(curl_handle); if (curl_res != CURLE_OPERATION_TIMEDOUT) break; retry_count--; if (curl_res == CURLE_OPERATION_TIMEDOUT) printf("curl_easy_perform failed. curl_res = %d, curl_strerror = %s\n", curl_res, curl_easy_strerror(curl_res)); ret = -3; http_code = 0; curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &http_code); if (curl_res == CURLE_OK && http_code == 200) * Now, our receive_content.memory points to a memory block that is receive_content.size * bytes big and contains the remote file. * Do something nice with it! getContent(receive, &rlen); char *response = (char*)handler->response.resize(rlen, rlen + 4, false); memset(response, '\0', rlen+4); memcpy(response, receive, rlen); response[rlen] = '\0'; httpCpde = getHttpCode(); handler->http_code = httpCpde; printf("sendReceive() <<< Data : \n%s\n[response data len : %d]\n", handler->response.getData(), handler->response.getSize()); ret = 0; printf("curl_easy_perform failed. curl_res = %d, Httpcode = %ld, curl_strerror = %s\n", curl_res, http_code, curl_easy_strerror(curl_res)); return -4; return ret; int HttpRequest::getHttpCode() return http_code; int HttpRequest::getHeader(char *header, unsigned int *len) if (receive_header.size > *len) return -5; memcpy(header, receive_header.memory, receive_header.size); *len = receive_header.size; return 0; int HttpRequest::getContent(char *content, unsigned int *len) if (receive_content.size > *len) return -5; memcpy(content, receive_content.memory, receive_content.size); *len = receive_content.size; return 0;
#include <stdio.h> #include "httpConn.h" // 封装自己的客户端 int customizeSendReceive(const char *url) int ret = 0; HttpRequest req; int httpCpde = 0; char receive[204800] = { 0 }; unsigned int rlen = sizeof(receive); int urlLen = strlen(url); if (0 >= urlLen) break; ret = req.setRequestUrl(url); if (0 != ret) break; ret = req.performRequest(); if (0 != ret) break; httpCpde = req.getHttpCode(); ret = req.getContent(receive, &rlen); if (0 != ret) break; } while (0); if (0 == ret && 200 == httpCpde) printf("ReceivevData :"); for (int i = 0; i < rlen; i++) printf("%c", receive[i]); printf("\n"); printf("sendReceive() failed.\n"); return ret; // 使用httpClient已经实现的客户端 void testSys(const char *url, const char *post_data) HttpRequest m_Conn; RequestHandler handler; handler.request.resize(0); handler.response.resize(0); int rlen = strlen(data); char *request = (char*)handler->request.resize(rlen, rlen + 4, false); memset(request, '\0', rlen+4); memcpy(request, post_data, rlen); int ret = m_Conn.sendReceiveEx(url, &handler); if (0 != ret) printf("sendReceiveEx failed, ret = %d\n", ret); printf("response data : %s\n", (char *)handler.response.getData()); int main(int argc, char *argv[]) //customizeSendReceive("www.xxx.com?xxxxxx#"); //testSys("www.xxx.com", "?...#"); return 0; 前面的文章《Libcurl编译指南——Android和Windows系统》已经就libcurl在Windows和Android系统编做了详细的说明。本文档用C/C++实现简单的HTTP/HTTPS客户端,支持get和post,支持保持session和长连接。httpConn.h#ifndef __HTTP_CONN_H__#define __HTTP_CONN_H__#include ...