2010-12-15 101 views
6

我在C++中使用libcurl,我使用Boost.Thread从我的UI中的一个单独的线程中调用curl_easy_perform如何立即取消卷曲操作?

主用户界面有一个取消按钮,我想完全响应(即,当用户点击它时,它应该立即作出反应)。我有读,写和进步设念原子should_cancel变量回调(如this问题),但有两个问题:

  1. 有经常当取消一个非常小的(但明显的)延迟在卷曲操作完成时按下。

  2. 偶尔会有很长的(有时是无休止的)延迟。在这种情况下,要么:

    a。进度,读取和回写简单地不会很长时间,或者

    b。进度回调调用后,我返回一个非零值(意思是它应该终止),但是curl操作一段时间没有完成(实际上,进程函数再次被调用!)

所以:

  1. 为什么长延迟发生(尤其是没有调用进度功能)?
  2. 我应该怎么做,而不是让取消按钮反应正常?

一种可能性是告诉UI取消操作成功,但在后台继续运行curl线程直到取消为止。这个问题(我认为)是它强制should_cancel变量是全局变量,而不是作用域开始的对话框。

+0

如何使用非阻塞curl_multi_perform HTTP://curl.haxx.se/libcurl/c/curl_multi_perform.html – 2014-02-24 19:31:54

回答

3

您的基本想法是正确的。您应该从UI中分离卷曲操作。但是,实施应该稍微改变。你不应该使用全球should_cancel。相反,您应该有一个全局的current_request指针,指向Request类型的对象。此类型应具有内部cancel标志和公共Cancel()函数。作为对取消按钮的响应,您可以拨打current_request上的Cancel,然后将其清空。然后取消的请求会在稍后进行自己的清理(毕竟它是一个线程)。

你需要小心你的互斥体以防止僵尸对象。取消和请求完成之间存在固有的竞争条件。

1

可能发生延迟,因为curl_easy_perform忙于写入或读取回调,请尝试从写入回调中返回0或从读取回调中返回CURL_READFUNC_ABORT。根据文档,如果写回调返回的值与函数收到的值不同,则传输将中止,并且如果读回调返回CURL_READFUNC_ABORT,则传输也会中止(从版本7.12.1开始有效图书馆)。

+0

我!我将“取消”返回码传递给所有三个回调(读取,写入和进度),但在第一个“长时间延迟”情况下没有调用任何回调。 – 2010-12-16 00:42:04

9

我遇到了与curl 7.21.6相同的问题。当时要中止smtp协议。 从读取回调中返回CURL_READFUNC_ABORT将停止传输,但curl_easy_perform在接下来的5分钟内不会返回。可能它会等待tcp超时。

要绕过我的存储由curl使用的套接字(替换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 
     } 
...