C++ 从不同线程执行curl\u multi\u perform导致崩溃
在我正在进行的项目中,我需要在必要时拨打GET电话和POST电话。“GET”调用用于创建从服务器到设备的下行通道,以监视云服务器中发生的任何有趣事件。“POST”调用用于将数据发送到服务器。服务器有一个限制,即只需与服务器保持一个连接。因为服务器支持HTTP2,所以我使用“CURLMOPT\u MAX\u HOST\u CONNECTIONS”,通过将其设置为1,我将CURL设置为使用1个连接,我使用CURLMOPT\u管道,通过将其设置为CURLPIPE\u MULTIPLEX,我将多路传输。问题是,在第二个线程上调用“curl\u multi\u perform”时,代码崩溃 PS:这是我原始代码的一部分,可能不会立即编译/运行C++ 从不同线程执行curl\u multi\u perform导致崩溃,c++,multithreading,curl,libcurl,nghttp2,C++,Multithreading,Curl,Libcurl,Nghttp2,在我正在进行的项目中,我需要在必要时拨打GET电话和POST电话。“GET”调用用于创建从服务器到设备的下行通道,以监视云服务器中发生的任何有趣事件。“POST”调用用于将数据发送到服务器。服务器有一个限制,即只需与服务器保持一个连接。因为服务器支持HTTP2,所以我使用“CURLMOPT\u MAX\u HOST\u CONNECTIONS”,通过将其设置为1,我将CURL设置为使用1个连接,我使用CURLMOPT\u管道,通过将其设置为CURLPIPE\u MULTIPLEX,我将多路传输。
#include <stdio.h>
#include <string>
#include <sstream>
#include <curl.h>
#include <pthread.h>
#define EVENTS_URL "https://avs-alexa-na.amazon.com/v20160207/events"
#define DOWNCHANNEL_URL "https://avs-alexa-na.amazon.com/v20160207/directives"
CURLM *multi_handle;
CURL *downchannel_handle;
CURL *eventHttp_handle;
size_t processDownchannelResponse(void *ptr, size_t size, size_t nmemb, void *instance)
{
printf(" There is downchannel response.");
}
size_t eventResponse(void *ptr, size_t size, size_t nmemb, void *instance)
{
printf("We got eventResponse");
}
/* The downchannel thread needs to be running always
, if the transfer is done the connection is closed
we need to open a new connection and wait for more events*/
void createDownchannel()
{
int retryCount =0;
std::string downchURL = DOWNCHANNEL_URL;
long response_code;
int runninghandles =0;
downchannel_handle = curl_easy_init();
if(downchannel_handle == NULL){
printf("createDownchannel : Not able to create curl handle");
return ;
}
struct curl_slist *header = NULL;
header = curl_slist_append(header, "Host: avs-alexa-na.amazon.com");
header = curl_slist_append(header, "TOKEN GOES HERE");
curl_easy_setopt(downchannel_handle, CURLOPT_URL, downchURL.c_str());
curl_easy_setopt(downchannel_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(downchannel_handle, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(downchannel_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
curl_easy_setopt(downchannel_handle, CURLOPT_WRITEFUNCTION, processDownchannelResponse);
curl_easy_setopt(downchannel_handle, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(downchannel_handle, CURLOPT_PIPEWAIT, 1L);
if (header)
curl_easy_setopt(downchannel_handle, CURLOPT_HTTPHEADER, header);
if(multi_handle)
/* add the individual easy handle */
curl_multi_add_handle(multi_handle, downchannel_handle);
mbexitdownchannelthread = 1;
do{
CURLMcode mc;
int numfds;
mc = curl_multi_perform(multi_handle, &runninghandles);
if(mc != CURLM_OK) {
fprintf(stderr, "curl_multi failed, code %d.n", mc);
printf(“a<---curl_multi failed, code %d.n", mc);
break;
}
printf("a<--downchannel while");
// downchannel timeout can be higher 10 seconds
mc = curl_multi_wait(multi_handle, NULL, 0, 10000, &numfds);
if(mc != CURLM_OK) {
fprintf(stderr, "curl_multi failed, code %d.n", mc);
printf("a<---curl_multi failed, code %d.n", mc);
break;
}
}while(!mbexitdownchannelthread);
curl_multi_remove_handle(multi_handle, downchannel_handle);
curl_easy_cleanup(downchannel_handle);
if (header)
curl_slist_free_all(header);
}
bool getTransferStatus(CURLM *multiHandleInstance,CURL *currentHandle,std::string& contentType,int* http_status_code)
{
//check the status of transfer CURLcode return_code=0;
int msgs_left=0;
CURLMsg *msg=NULL;
CURL *eh=NULL;
CURLcode return_code;
bool msgTrasferDone = false;
while ((msg = curl_multi_info_read(multiHandleInstance, &msgs_left)))
{
if (msg->msg == CURLMSG_DONE) {
eh = msg->easy_handle;
if(currentHandle == eh)
{
msgTrasferDone = true;
return_code = msg->data.result;
if(return_code!=CURLE_OK)
{
//fprintf(stderr, "CURL error code: %d\n", msg->data.result);
printf("a<--return_code!=CURLE_OK CURL error code: %d\n", msg->data.result);
continue;
}
// Get HTTP status code
*http_status_code=0;
char* ch= NULL;
curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, http_status_code);
printf("a<--CURLINFO_RESPONSE_CODE=%d",*http_status_code);
curl_easy_getinfo(eh, CURLINFO_CONTENT_TYPE, &ch);
contentType.clear();
if(ch!=NULL)
contentType.append(ch);
}
}
}
return msgTrasferDone;
}
int eventThread()
{
int still_running = 0;
std::string contentType;
int responseCode = 0;
int numfds = 0;
std::string postUrl;
postUrl.assign(EVENTS_URL);
// init the curl session
CURL *eventHttp_handle;
CURLcode res;
eventHttp_handle = curl_easy_init();
//assign speech buffer pointer for read callbacks
curl_easy_setopt(eventHttp_handle, CURLOPT_URL, postUrl.c_str());
curl_easy_setopt(eventHttp_handle, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(eventHttp_handle, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(eventHttp_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
/* wait for pipe connection to confirm */
curl_easy_setopt(eventHttp_handle, CURLOPT_PIPEWAIT, 1L);
curl_easy_setopt(eventHttp_handle, CURLOPT_WRITEFUNCTION, eventResponse);
curl_easy_setopt(eventHttp_handle, CURLOPT_WRITEDATA, NULL);
struct curl_slist *header = NULL;
header = curl_slist_append(header, "Host: avs-alexa-na.amazon.com");
header = curl_slist_append(header, "TOKEN GOES HERE");
if (header)
curl_easy_setopt(eventHttp_handle, CURLOPT_HTTPHEADER, header);
if (multi_handle)
curl_multi_add_handle(multi_handle, eventHttp_handle);
do
{
{
CURLMcode mc;
int numfds;
mc = curl_multi_perform(multi_handle, &still_running);
if(mc != CURLM_OK) {
fprintf(stderr, "curl_multi failed, code %d.n", mc);
printf("a<---curl_multi failed, code %d.n", mc);
break;
}
mc = curl_multi_wait(multi_handle, NULL, 0, 1000, &numfds);
if(mc != CURLM_OK) {
fprintf(stderr, "curl_multi failed, code %d.n", mc);
printf("a<---curl_multi failed, code %d.n", mc);
break;
}
}
}while(!getTransferStatus(multi_handle,eventHttp_handle,contentType,&responseCode));
if (header)
curl_slist_free_all(header);
if (formpost)
{
curl_formfree(formpost);
formpost = NULL;
}
printf("a<-- CURL HTTP RESP CODE =%d",responseCode);
curl_multi_remove_handle(multi_handle, eventHttp_handle);
curl_easy_cleanup(eventHttp_handle);
return 0;
}
int main ()
{
multi_handle = curl_multi_init();
curl_multi_setopt(multi_handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
curl_multi_setopt(multi_handle, CURLMOPT_MAX_HOST_CONNECTIONS, 1L);
// create a downchannel thread
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int err = pthread_create(&mPostThread, &attr, downchannelThread,NULL);
pthread_attr_destroy(&attr);
// i am doing some work here //
sleep(3);
// create a event thread
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int err = pthread_create(&mPostThread, &attr, eventThread,NULL);
pthread_attr_destroy(&attr);
}
#包括
#包括
#包括
#包括
#包括
#定义事件\u URL“https://avs-alexa-na.amazon.com/v20160207/events"
#定义下行通道\u URL“https://avs-alexa-na.amazon.com/v20160207/directives"
CURLM*多U手柄;
卷曲*下通道_手柄;
CURL*eventHttp_句柄;
大小\u t processDownchannelResponse(void*ptr、大小\u t size、大小\u t nmemb、void*实例)
{
printf(“存在下行通道响应”);
}
大小事件响应(void*ptr、大小、大小nmemb、void*实例)
{
printf(“我们得到了eventResponse”);
}
/*下行通道线程需要始终运行
,如果传输完成,则连接关闭
我们需要打开新连接并等待更多事件*/
void createDownchannel()
{
int retryCount=0;
std::string downchURL=下行通道URL;
长响应编码;
int runninghandles=0;
下通道句柄=curl\u easy\u init();
if(下行通道_句柄==NULL){
printf(“createDownchannel:无法创建卷曲句柄”);
返回;
}
struct curl_slist*header=NULL;
header=curl\u slist\u append(header,“主机:avs-alexa na.amazon.com”);
header=curl\u slist\u append(header,“TOKEN在这里”);
curl_easy_setopt(下行通道句柄,CURLOPT_URL,downchURL.c_str());
curl\u easy\u setopt(下行通道句柄,CURLOPT\u SSL\u验证对等,0L);
curl\u easy\u setopt(下行通道句柄,CURLOPT\u SSL\u验证主机,0L);
curl\u easy\u setopt(下行通道句柄、CURLOPT\u HTTP\u版本、curl\u HTTP\u版本2\u先验知识);
curl\u easy\u setopt(下行通道句柄、CURLOPT\u WRITEFUNCTION、processDownchannelResponse);
curl_easy_setopt(下行通道句柄,CURLOPT_WRITEDATA,NULL);
卷曲轻松设置(下通道手柄,卷曲管等待,1L);
如果(标题)
curl_easy_setopt(下行通道手柄、CURLOPT_HTTPHEADER、header);
if(多线程句柄)
/*添加单独的易处理*/
卷曲多加控制柄(多控制柄、下通道控制柄);
mbexitdownchannelthread=1;
做{
卷曲码mc;
int-numfds;
mc=curl\u multi\u perform(多句柄和运行句柄);
如果(mc!=CURLM_OK){
fprintf(标准,“卷曲多个失败,代码%d.n”,mc);
printf(“a”代码崩溃)-此时您要做的第一件事是在设置调试器时检查代码。然后,在调试器中运行代码,复制崩溃并检查调用堆栈和变量,以查看您对代码执行行为的假设与实际行为的不同之处。我个人首先要验证每个调用是否返回成功的结果()。嗨,Craig,我知道代码在哪里崩溃,代码在第二个线程上调用“curl\u multi\u perform”时崩溃。听起来你好像没有遵守这一点:嗨,Daniel,很高兴再次与你互动。从你发送的链接来看,“在多个线程中,你永远不能共享同一个句柄”这是否意味着我不能在不同的线程中将句柄添加到同一个multi_句柄并调用CURLmulti_perform?@DanielStenberg你能帮忙吗,我有点被困在如何处理这个问题上。