在C中使用摘要授权的Libcurl:定期发送http请求

时间:2013-10-15 13:47:26

标签: c multithreading libcurl alarm digest

我正在开发一个使用P(an)T(ilt)Z(oom)摄像机跟踪对象的系统,该摄像机可以通过HTTP请求进行控制。我开发的C应用程序应该接收被跟踪对象的位置数据并向摄像机发送命令以控制摇摄和倾斜角度。除了这些命令,摄像机还必须每5秒接收一次会话刷新命令。必须使用HTTP摘要授权进行连接。

我正在使用libcurl发送HTTP请求。我已经知道,对于digest auth,需要使用on和所有请求in this stackoverflow post的相同curl句柄。
为了定期发送会话刷新命令,我尝试使用一个刚刚执行此操作的线程:

while(1)
{
    usleep(5000000);
    sessionContinue(g_Config.cam_ip);
}

sessionContinue看起来像这样:

CURLcode sessionContinue(char* url)
{
   CURLcode res;
   char requestURL[40];
   char referer[47];
   struct curl_slist *headers=NULL;

   strcpy(requestURL , url);
   strcat(requestURL, CAM_SESSION_CONTINUE);

   strcpy(referer , "Referer: http://");
   strcat(referer , url);
   strcat(referer , CAM_MONITOR);

   headers = curl_slist_append(headers,"Connection:keep-alive");
   headers = curl_slist_append(headers, camCookie);

   // In windows, this will init the winsock stuff
   curl_global_init(CURL_GLOBAL_ALL);

   curl_easy_reset(curl);
   if(curl) 
   {
    // First set the URL that is about to receive our POST. This URL can
    //just as well be a https:// URL if that is what should receive the
    //data.

    curl_easy_setopt( curl , CURLOPT_URL        , requestURL                        );
    curl_easy_setopt( curl , CURLOPT_HTTPHEADER , headers                           );
    curl_easy_setopt( curl , CURLOPT_HTTPGET    , 1                                 );
    curl_easy_setopt( curl , CURLOPT_USERNAME   , "root"                            );
    curl_easy_setopt( curl , CURLOPT_PASSWORD   , "password"                        );
    curl_easy_setopt( curl , CURLOPT_HTTPAUTH   , CURLAUTH_BASIC | CURLAUTH_DIGEST  );

    // Perform the request, res will get the return code
    res = curl_easy_perform(curl);

    // Check for errors
    if(res != CURLE_OK)
        fprintf(stderr, "curl_easy_perform() failed @ %s:%d : %s\n",  curl_easy_strerror(res) , __FILE__ , __LINE__ );
    }

return res;
}

执行curl_easy_perform(curl)后,应用程序始终因分段错误而崩溃。所以我再次阅读了libcurl教程,现在我知道using one curl handle in multiple threads is a no go

我尝试的是使用带SIGALRM的计时器来实现定期会话刷新。这并没有改变curl_easy_perform(curl)崩溃的问题。奇怪的是,当发送正常命令来控制使用相同卷曲手柄的摇摄和倾斜位置时,应用程序不会崩溃。会话刷新和平移/倾斜命令之间的唯一区别是会话刷新使用GET,平移/倾斜使用POST。

是否有其他可能连续发送摇摄/倾斜命令,每5秒发送一次短暂停顿以发送会话刷新?

2 个答案:

答案 0 :(得分:1)

您在一个小程序中遇到了很多问题。这里有几个:

  1. 您可能会使用您使用的危险无界C函数溢出其中一个小的固定大小缓冲区。很可能其中一个是段错误的原因。
  2. 记录
  3. curl_global_init()被称为一次,你反复调用它 - 这甚至不需要在它们之间调用curl_global_cleanup()。你显然在函数的某个地方调用curl_easy_init(),你应该在那里移动全局init。
  4. 'referer'充满了数据但从未使用
  5. 另一个建议是使用CURLOPT_ERRORBUFFER来获取错误消息而不是curl_easy_strerror(),因为您可能会获得一些额外的细节。当然,在调试请求时设置CURLOPT_VERBOSE,看看事情看起来像你想要的那样。

答案 1 :(得分:0)

感谢Daniel Stenberg的评论。我现在在设置句柄时只调用curl_global_init()一次。这里并不真正需要referer,但我在忘记密码之前忘记删除它。

分段错误的原因是会话刷新命令和平移和倾斜命令试图同时使用同一个卷曲句柄,这显然不能真正起作用。所以定时器和SIGALRM的解决方案不是问题。通过添加互斥锁来解决分段错误,以避免对卷曲句柄的并发访问。