Introduction
Under Windows platform, organize an HTTP request with C++ code may cost plenty of time. This article will introduce curl to you to solve this problem.
Background
CURL is an opensource lib under Windows which is used to send and receive http packages. We can easily complete http tasks with lib curl.
Using the Code
This tip may not provide a completed project or source code for you to compile and run. I will introduce how to use the libcurl
with C++ project. I will list some key codes at the same time.
1. Getting Started with Lib CURL
1.1 Download CURL & Compile
We can get the latest version of CURL at http://curl.haxx.se/download.html. The latest version I use is the 7.45.0.I get the source code package for Windows: curl-7.45.0.zip.
After you finished downloading, unzip the package at E:\ThirdPartyLib\curl-7.45.0. We can find the VS project file under the path: E:\ThirdPartyLib\curl-7.45.0\projects\Windows. Open the project file with Visual Studio and compile the source code as a lib or DLL.
When you compile the source code, you may get some errors that can't find the openssl or libssh2. You can get the openssl at http://www.openssl.org/source/. libssh can be downloaded through your search engine.
P.S.: Compile the opensll may need the ActivePerl.
1.2 Insert the CURL into Your Project
If you successfully compiled the source code, you will get the libcurld.lib for debug or libcurl.lib for release. Just copy this lib to your project library directory and include this lib.
2. Synchronous and Asynchronous Operation in CURL
When send http request to the server, there will two different kinds of conditions.
2.1 You send some simple request such as update a parameter's value
This kind of request usually needs immediate reply.The CURL provides the synchoronous method curl_easy_perform
to handle this.
2.2 You want to download from server through your request
This kind of request may cost some time for the server to operate. So we can't get a reply right now. The asynchronous method curl_multi_init
can apply a multi-thread space to run this kind of request. If you want to add a request to the multi-thread space, use the curl_multi_add_handle
. curl_multi_perform
is used to make the multi-thread space begin to run, but you need to call this method continuously to motivate the multi-thread space if there are any requests that are not finished.
3. Pack your HTTP Request Up
I will display a POST
example to show how to pack http request with CURL.
CURL* pHandle =curl_easy_init();
curl_easy_setopt(pHandle,CURLOPT_URL,Url);
curl_easy_setopt(pHandle,CURLOPT_TIMEOUT,timeout);
curl_easy_setopt(pHandle,CURLOPT_POST,1L);
The code above completes a simple http request head which only includes the request address, timeout and http type:POST
.
Then, we should add the request body which shows what you want the server to do to the request. If your request doesn't contain any enclosure, we just need to set the Postfields
:
curl_easy_setopt(pHandle,CURLOPT_POSTFIELDS,requesuList);
The requestList
is the url-encode
: a list of key=value string
split with the ‘&
‘. For example: "Name=test&Password=123&Type = 1
"
After these steps, a simple http post request is packed up. Call curl_easy_perform
to run.
If our request contains an enclosure, we should change the packing up method.
CURL* pHandle =curl_easy_init();
curl_easy_setopt(pHandle,CURLOPT_URL,Url);
curl_easy_setopt(pHandle,CURLOPT_TIMEOUT,timeout);
The header seems to be the same, but the posttype doesn't need to be set. Because of the enclosure, we should use the multi-part to organize the http package. The postfields
above should be post in multi-part too.
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, Key,
CURLFORM_COPYCONTENTS, Value,
CURLFORM_END);
The key and value represent the "key = value
" pair in the postfields. If there is more than one pair, you can call a loop to add like the example above.
Then, we will add the file information:
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "filename",
CURLFORM_COPYCONTENTS, FileName,
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "size",
CURLFORM_COPYCONTENTS, FileSize,
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "fileContent",
CURLFORM_FILE, filepath,
CURLFORM_END);
The form is the same with the example above. If you don't know what CURLFORM_COPYNAME
to insert, you should ask your server.
If there is more than one file, call loop to insert.
After you finish the multi-part form, we should add this form to the CURL handle:
curl_easy_setopt(pHandle,CURLOPT_HTTPPOST,formpost);
Till now, a basic CURL based http request is packed up. But there comes a problem: How to get the upload progress?
The CURL provides many options for the developer to set to monitor the status of the http request:
curl_easy_setopt(pHandle,CURLOPT_NOPROGRESS,0L);
curl_easy_setopt(pHandle,CURLOPT_PROGRESSFUNCTION,getProgress);
curl_easy_setopt(pHandle,CURLOPT_PROGRESSDATA,data);
These three codes open the progress switch. Set the call back function getprogress
and the data send to the callback: data
. You can find the function definition of the getProgress
in the header files.
At the same time, if your request is downloading file, you may need to set the WRITEDATA
options:
curl_easy_setopt(pHandle, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(pHandle, CURLOPT_WRITEDATA, data);
Now, the request is finished.
4.Get the http request Execute Result
If you call the curl_easy_perform
, your request will be executed immediately.
curl_easy_getinfo(pHandle,CURLINFO_HTTP_CODE,&HttpReturnCode);
curl_easy_getinfo
can give you many returned status of the request.
If you call the curl_multi_perform
, your request may be executed later. These codes show how to manage the running status of the request:
do{
curl_multi_perform(m_phttpQuestList, &RunningNum);
URLMcode mc;
int numfds;
mc = curl_multi_wait(m_phttpQuestList, NULL, 0, 1000, &numfds);
if(mc != CURLM_OK)
{
break;
}
if(!numfds)
{
repeats++;
if(repeats > 1)
{
Sleep(100);
}
}
else
repeats = 0;
int msgs_left;
CURLMsg * msg;
while((msg = curl_multi_info_read(m_phttpQuestList, &msgs_left)))
{
if (CURLMSG_DONE == msg->msg)
{
....
}
}
} while(RunningNum);
curl_multi_perform
will insert the number of requests remaining in the running thread into RunningNum
. If the RunningNum
is greater than 0
, you should call the curl_multi_perform
continuously. The curl_multi_info_read
can get if there is any request finished.
OK, that's all.
History
- 2015.11.26: The first edition