2010-12-15 9 views
6

मैं सी ++ में libcurl का उपयोग कर रहा हूं, और मैं Boost.Thread का उपयोग कर अपने यूआई से अलग थ्रेड में curl_easy_perform पर कॉल कर रहा हूं।मैं तुरंत कर्ल ऑपरेशन कैसे रद्द कर सकता हूं?

मुख्य यूआई में एक रद्द बटन है जो मैं पूरी तरह उत्तरदायी होना चाहता हूं (यानी, जब कोई उपयोगकर्ता उस पर क्लिक करता है, तो उसे तुरंत प्रतिक्रिया देनी चाहिए)। मैंने पढ़ा है, लिखते हैं, और एक परमाणु should_cancel चर को पढ़ने के लिए की स्थापना की कॉलबैक (this प्रश्न के रूप में) के लिए प्रगति, लेकिन वहाँ दो समस्याएं हैं:

  1. अक्सर जब रद्द से एक बहुत छोटे (लेकिन ध्यान देने योग्य) देरी नहीं है कर्ल ऑपरेशन पूरा होने पर दबाया जाता है।

  2. कभी-कभी, बहुत लंबा (कभी-कभी अंतराल) देरी होती है। इस मामले में, या तो:

    ए। कॉलबैक की प्रगति, पढ़ना और लिखना लंबे समय तक नहीं कहा जाता है, या

    बी। प्रगति कॉलबैक कहा जाता है, मैं एक nonzero मान (जिसका अर्थ है इसे समाप्त करना चाहिए) लौटाता है, लेकिन कर्ल ऑपरेशन थोड़ी देर के लिए पूरा नहीं होता है (वास्तव में, प्रगति समारोह इस दौरान फिर से कहा जाता है!)

तो:

  1. क्यों बहुत ज़्यादा समय लग (विशेष रूप से प्रगति फ़ंक्शन कॉल के बिना) होता है?
  2. रद्द करने के बटन को ठीक तरह से प्रतिक्रिया देने के लिए मुझे क्या करना चाहिए?

एक संभावना यूआई को बताना है कि रद्द करने का ऑपरेशन सफल हुआ, लेकिन जब तक यह रद्द नहीं हो जाता तब तक पृष्ठभूमि में कर्ल थ्रेड चलाते रहें। इसके साथ समस्या (मुझे लगता है) यह है कि यह should_cancel वैरिएबल को ग्लोबल होने के लिए मजबूर करता है, ऑपरेशन शुरू होने पर डायलॉग बॉक्स पर जाने के बजाए।

+0

कैसे गैर अवरुद्ध curl_multi_perform उपयोग के बारे में http: –

उत्तर

3

आपका मूल विचार सही है। आपको यूआई से कर्ल ऑपरेशन को अलग करना चाहिए। हालांकि, कार्यान्वयन थोड़ा बदलना चाहिए। आपको वैश्विक should_cancel का उपयोग नहीं करना चाहिए। इसके बजाय, आपके पास Request प्रकार की ऑब्जेक्ट पर वैश्विक current_request सूचक होना चाहिए। इस प्रकार में एक आंतरिक cancel ध्वज होना चाहिए, और एक सार्वजनिक Cancel() फ़ंक्शन होना चाहिए। रद्द करें बटन के जवाब में, आप Cancel पर current_request पर कॉल करें और फिर इसे शून्य करें। एक रद्द अनुरोध तब बाद में अपने स्वयं के सफाई के लिए प्रतिकूल है (यह सब के बाद एक धागा है)।

आपको ज़ोंबी वस्तुओं को रोकने के लिए अपने म्यूटेक्स से सावधान रहना होगा। रद्द करने और अनुरोध पूर्ण होने के बीच एक अंतर्निहित रेस स्थिति है।

1

देरी हो सकती है क्योंकि curl_easy_perform लिखने या पढ़ने के कॉलबैक में व्यस्त है, पढ़ने कॉलबैक से 0 को वापस करने का प्रयास करें या CURL_READFUNC_ABORT पढ़ने कॉलबैक से वापस लौटने का प्रयास करें। दस्तावेज़ीकरण के मुताबिक, अगर कॉलबैक द्वारा लौटाया गया मान फ़ंक्शन द्वारा प्राप्त मूल्य से भिन्न होता है तो हस्तांतरण निरस्त कर दिया जाएगा, और यदि रीड कॉलबैक CURL_READFUNC_ABORT लौटाता है, तो हस्तांतरण भी निरस्त कर दिया जाएगा (संस्करण 7.12.1 से मान्य पुस्तकालय)।

+0

//curl.haxx.se/libcurl/c/curl_multi_perform.html मैं कर रहा हूँ! मैं सभी तीन कॉलबैक (पढ़ने, लिखने और प्रगति) में "रद्द करें" रिटर्न कोड पास कर रहा हूं, लेकिन पहले "लंबे विलंब" मामले में कॉलबैक में से कोई भी कॉल नहीं किया जाता है। –

9

मैं वही 7.21.6 के साथ एक ही समस्या से मुलाकात की। Smtp प्रोटोकॉल को रद्द करने के लिए tring जब। रीड कॉलबैक से CURL_READFUNC_ABORT लौटने से स्थानांतरण बंद हो जाता है लेकिन curl_easy_perform अगले 5+ मिनटों के लिए वापस नहीं आता है। शायद यह टीसीपी टाइमआउट के लिए इंतजार कर रहा है।

इसे चारों ओर चलने के लिए मैं कर्ल द्वारा उपयोग की गई सॉकेट को स्टोर करता हूं (curl_opensocket_callback को प्रतिस्थापित करें), और आवश्यकता होने पर सीधे इस सॉकेट को बंद करें।

curl_socket_t storeCurlSocket(SOCKET *data, curlsocktype purpose, struct curl_sockaddr *addr) { 
    SOCKET sock = socket(addr->family, addr->socktype, addr->protocol); 
    *data = sock; 
    return sock; 
} 

size_t abort_payload(void *ptr, size_t size, size_t nmemb, SOCKET *curl_socket) { 
    SOCKET l_socket = INVALID_SOCKET; 
    swap(l_socket, *curl_socket); 
    if (l_socket != INVALID_SOCKET) { 
     shutdown(l_socket, SD_BOTH); 
     closesocket(l_socket); 
    } 
    return CURL_READFUNC_ABORT; 
} 

...calling perform... 
     SOCKET curlSocket; 
     curet = curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, storeCurlSocket); 
     curet = curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &curlSocket); 
     curet = curl_easy_setopt(curl, CURLOPT_READFUNCTION, abort_payload); 
     curet = curl_easy_setopt(curl, CURLOPT_READDATA, &curlSocket); 
     curet = curl_easy_perform(curl); 
     if (curet == CURLE_ABORTED_BY_CALLBACK) { 
      //expected abort 
     } 
... 

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^