最近使用C++做一些编程,JAVA中采用HTTP协议通信很简单,我们熟知的HTTPClient就可以完成通信。在C++中BOOST库仅仅将TCP/UDP协议进行了很好的封装,但是HTTP需要我们自己在编写一部分代码才能很好的同步HTTP来完成客户端与服务器端的信息交互。libcurl对HTTP等协议进行了很好的封装,于是采用libcurl来完成图片上传的功能。
1.libcurl简单认识
libcurl支持用不同的协议连接和沟通不同的服务器,其支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议。libcurl是C++中比较好的网络交互的库。
libcurl下载地址为:http://curl.haxx.se/download.html
libcurl 在线API地址为:http://curl.haxx.se/libcurl/c/
libcurl 接口介绍(中文)为:http://blog.csdn.net/fengshuiyue/article/details/39530093
2.libcurl图片上传源码
InnoVSSImgSendStateType InnoVSSImgNetStorage::NetStorageImg(PicStorageModel& picStorageModel)
{
curl = curl_easy_init();
multi_handle = curl_multi_init();
int still_running;
struct curl_httppost *formpost=NULL;
struct curl_httppost *lastptr=NULL;
struct curl_slist *headerlist=NULL;
static const char buf[] = "Expect:";
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile",
CURLFORM_FILE, picStorageModel.picInfo.localPath.c_str(),
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "filename",
CURLFORM_COPYCONTENTS, picStorageModel.picInfo.fullView.c_str(),
CURLFORM_END);
std::string imageInfo;
picStorageModel.postInfo.getImageInfoXml(imageInfo);
imageInfo = StringEncode::GBKToUTF8(imageInfo);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "imageInfo",
CURLFORM_COPYCONTENTS, imageInfo.c_str(),
CURLFORM_END);
std::string urlPath = picStorageModel.urlRequestPath;
//headerlist = curl_slist_append(headerlist, "Accept-Encoding:UTF-8");
//headerlist = curl_slist_append(headerlist, "Content-type: application/form-data;charset:UTF-8");
headerlist = curl_slist_append(headerlist, buf);
if(curl && multi_handle) {
curl_easy_setopt(curl, CURLOPT_URL, urlPath.c_str());
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
//curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION,headerfunction);
ImgNetStorageResultModel resultModel;
resultModel.picStorageModel = picStorageModel;
resultModel.imgNetStorage = this;
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resultModel);
curl_multi_add_handle(multi_handle, curl);
CURLMcode curlm_code = CURLM_CALL_MULTI_PERFORM;
curlm_code = curl_multi_perform(multi_handle, &still_running);
int count = 0;
int responseCode = 0;
do {
struct timeval timeout;
int rc;
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd = -1;
long curl_timeo = -1;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
curl_multi_timeout(multi_handle, &curl_timeo);
if(curl_timeo >= 0) {
timeout.tv_sec = curl_timeo / 1000;
if(timeout.tv_sec > 1)
timeout.tv_sec = 1;
else
timeout.tv_usec = (curl_timeo % 1000) * 1000;
}
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc) {
case -1:
count++;
break;
case 0:
default:
LOGD << "正在上传图片....." << zhxy_log::endl;
curlm_code = curl_multi_perform(multi_handle, &still_running);
if (curlm_code == CURLM_OK){
CURLcode res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
}
break;
}
} while(still_running&&count < _adapterConfig.timeOutCount);
//if (curlm_code == CURLM_OK) {
// long code;
// CURLcode res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
// long connectCode;
// res = curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE, &connectCode);
// LOGD << "connectCode:" << connectCode << zhxy_log::endl;
//}
curl_formfree(formpost);
curl_slist_free_all (headerlist);
curl_multi_cleanup(multi_handle);
curl_easy_cleanup(curl);
multi_handle = NULL;
curl = NULL;
if (curlm_code != CURLM_OK) {
LOGD << "curlm_code:" << curlm_code << "\n" <<curl_multi_strerror(curlm_code);
return InnoVSSImgSendStateTypes::Failed;
}
if (responseCode != 200)
{
return InnoVSSImgSendStateTypes::Failed;
}
if (count>=_adapterConfig.timeOutCount)
{
return InnoVSSImgSendStateTypes::Failed;
}else{
return InnoVSSImgSendStateType::Success;
}
}
}
3.上传代码部分说明
1)在调试中发现不管图片服务器是否开启,curl_multi_perform(multi_handle, &still_running);返回值一直是成功,通过返回值无法捕获到上传是否成功。
2)代码中可以通过curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);获取http相应值,在退出循环后判断responseCode是否为200,是则上传成功,否则上传失败