libcurl使用教程
最近一个项目,使用libcurl来做HTTP CLIENT服务,踩了不少坑,特别分享一下这些坑。
我使用的是libcurl的同步接口,支持openssl,多线程环境。
1、环境初始化
使用libcurl时,首先要初始化libcurl的运行环境,退出应用时,也要清理环境。
应用加载时:curl_global_init(CURL_GLOBAL_ALL);
应用退出时:curl_global_cleanup();
2、多线程
多线程支持,每一个线程保持一个libcurl的句柄。这个很重要。不要混用,否则程序会出现莫名的crash。直接上线程代码。
static void* voice_thread_func(void* data) { CURL* curl1; curl1 = curl_easy_init(); wz_recog_channel_t* recog_channel = (wz_recog_channel_t*)(data); while(1) { pthread_mutex_lock(&recog_channel->mt); if (recog_channel->stop != 0) { apt_log(RECOG_LOG_MARK, APT_PRIO_INFO, "asr voice thread exit"); pthread_mutex_unlock(&recog_channel->mt); curl_easy_cleanup(curl1); return; } pthread_mutex_unlock(&recog_channel->mt); //apt_log(RECOG_LOG_MARK, APT_PRIO_INFO,"TOTAL:%d ",recog_channel->total_size); pthread_mutex_lock(&recog_channel->buffer_read_mt); int tmp_size = recog_channel->buffer_read + chunk_size; if (tmp_size > recog_channel->total_size) { pthread_mutex_unlock(&recog_channel->buffer_read_mt); usleep(10000); continue; } long current_pos = recog_channel->buffer_read; recog_channel->buffer_read += chunk_size; long seq = recog_channel->seq; recog_channel->seq++; pthread_mutex_unlock(&recog_channel->buffer_read_mt); apt_log(RECOG_LOG_MARK, APT_PRIO_INFO, "current_pos %d, seq %d, buffer_read %d, total_size %d",current_pos, seq, recog_channel->buffer_read, recog_channel->tota l_size); send_voice_asr(recog_channel, current_pos, seq, curl1); } }
3、https支持
证书机制,设置证书的位置,加载。
curl_easy_setopt(curl1, CURLOPT_SSL_VERIFYPEER,0);
curl_easy_setopt(curl1, CURLOPT_SSL_VERIFYHOST,0);
curl_easy_setopt(curl1, CURLOPT_SSLCERTTYPE,"PEM");
curl_easy_setopt(curl1, CURLOPT_SSLCERT, "client.pem");
curl_easy_setopt(curl1, CURLOPT_SSLKEY, "key.pem");
4、坑
如果多线程一定设置NOSIGAL,
curl_easy_setopt(curl1, CURLOPT_NOSIGNAL, 1L);
OPENSSL 连接异常会出现crash,后来检查发现是因为failf的故障日志导致的。这个bug找了好久。查找了 openssl.c才知道原因。
if(SSL_CTX_use_certificate_chain_file(ctx, cert_file) != 1) { failf(data, "could not load PEM client certificate, " OSSL_PACKAGE " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); return 0; }