zoukankan      html  css  js  c++  java
  • libcurl 中使用curl_multi_perform()函数执行订阅类型url的问题

    前提概要

    当需要同时处理多个url时,可采用curl_multi_perform方式执行,如下代码1: 

     1     //初始化一个multi curl 对象
     2     CURLM * curl_m = curl_multi_init();
     3     CURL * my_curl[CURL_NUM];
     4     char rcvbuf[CURL_NUM][MAXHEADLEN] = { 0 };
     5     //其他初始化代码略过...
     6     
     7     //执行多个url
     8     while(running_handles)
     9     {
    10         if (-1 == curl_multi_select(curl_m))
    11         {
    12             printf("curl_multi_select error !
    ");
    13             break;
    14         }
    15         else {
    16             // select监听到事件,调用curl_multi_perform通知curl执行相应的操作 //
    17             while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles));    
    18         }
    19     }
    20     
    21     //解析数据
    22     int  msgs_left;
    23     CURLMsg *  curl_msg;
    24     while((curl_msg = curl_multi_info_read(curl_m, &msgs_left)))
    25     {
    26         if (CURLMSG_DONE == curl_msg->msg)
    27         {
    28             int idx;
    29             for (idx = 0; idx < CURL_NUM; ++idx)
    30             {
    31                 if (curl_msg->easy_handle == my_curl[idx]) break;
    32             }
    33 
    34             if (idx == CURL_NUM)
    35             {
    36                 printf("curl not found !
    " );
    37             }
    38             else
    39             {
    40                 printf("
    curl[%d] rcvbuf:
    %s
    ", idx,rcvbuf[idx]);
    41                 //数据处理...
    42             }
    43         }
    44     }

    问题概要

    现在我的url为订阅方式,每个curl都会一直收数据(即使没数据也会每10s收到一帧心跳消息),永远不会退出,即上面的循环永远在执行,这样我无法运行到"解析数据"那一步。所以我需要在循环内判断某个curl是否有新数据到来

    方法1(不行)

    首先想到的方法是直接将curl_multi_info_read()函数直接移到循环内,看是否能受到数据,如下代码2:

     1     //执行多个url,并解析数据
     2     while(running_handles)
     3     {
     4         if (-1 == curl_multi_select(curl_m))
     5         {
     6             printf("curl_multi_select error !
    ");
     7             break;
     8         }
     9         else {
    10             // select监听到事件,调用curl_multi_perform通知curl执行相应的操作 //
    11             while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles));    
    12             //检测哪一个curl[idx]来的数据
    13             while ((curl_msg = curl_multi_info_read(curl_m, &msgs_left)))
    14             {
    15                 if (CURLMSG_DONE == curl_msg->msg)
    16                 {
    17                     int idx;
    18                     for (idx = 0; idx < CURL_NUM; ++idx)
    19                     {
    20                         if (curl_msg->easy_handle == my_curl[idx]) break;
    21                     }
    22                     if (idx == CURL_NUM)
    23                     {
    24                         printf("curl not found !
    " );
    25                     }
    26                     else
    27                     {
    28                         printf("
    curl[%d] rcvbuf:
    %s
    ", idx,rcvbuf[idx]);
    29                         //数据处理...
    30                         memset(rcvbuf[idx], 0, sizeof(rcvbuf[idx]));//清空buf下轮循环还要用
    31                     }
    32                 }
    33             }
    34         }
    35     }

         显然是我想多了,这样处理之后唯一的不同就是,哪个curl执行完了就打印哪个的数据(代码1的是只能等到所有的curl都执行完毕退出循环后依次打印rcvbuf[idx]),但我的curl是订阅的,根本执行不完,这样也没法打印,除非rcvbuf[idx]溢出...

    方法2(暂时不行)

      rcvbuf[idx]溢出?这样肯定不可能,但是让我想起了curl_easy_setopt()函数,这货可以配置curl的各种功能,或许总有一个能满足我吧:

    CURLOPT_TIMEOUT_MS 配置超时时间?
        不对,这个是要超时了curl直接挂了;
    CURLOPT_RANGE 配置断点续传?
        貌似可以;通过测试发现收指定XX个字节满了后该curl就退出了,即使后面还有数据他也不要了,这不是我们想看到的。
    还有一个接收超时时间的配置?
        同上,超过多少s后即使还有数据他也不要了,也不行。
    ...

    相信通过配置curl_easy_setopt()函数应该是最官方的做法,但小弟不才没有找到相关文章,自己研究也没搞出来,有待高人指点。

    方法3(可行,有缺陷)

    万般无奈之下,突然想到既然curl[idx]收到的数据在rcvbuf[idx]中,为何不直接检查rcvbuf[idx]中有没有数据,如下代码3:

     1     //执行多个url,并解析数据
     2     while(running_handles)
     3     {
     4         if (-1 == curl_multi_select(curl_m))
     5         {
     6             printf("curl_multi_select error !
    ");
     7             break;
     8         }
     9         else {
    10             // select监听到事件,调用curl_multi_perform通知curl执行相应的操作 //
    11             while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles));    
    12             //检测哪一个curl[idx]来的数据
    13             int idx = 0;
    14             for (idx = 0; idx < CURL_NUM; ++idx)
    15             {
    16                 if (rcvbuf[idx][0] == NULL) //curl[idx]没有收到数据。
    17                     continue;
    18                 printf("curl[%d] rcvbuf:
    %s
    ", idx, rcvbuf[idx]);
    19                 //数据处理...
    20                 memset(rcvbuf[idx], 0, sizeof(rcvbuf[idx]));
    21             }    
    22         }
    23     }

    通过上面的处理确实能满足要求,但是方法有些笨,存在2个明显的缺陷:
      1. 每次都要检测所有的curl一遍,效率低;
      2. 一旦某个curl因某种原因死掉了,我该如何判断是哪一个curl挂了?


    所以处理这个问题是否有官方的方法?还有待高人解答,保持关注更新。




  • 相关阅读:
    liunx命令二
    移动App专项测试
    web安全性测试用例
    jmeter分布式测试的坑(转)
    全新linux中通过编译方式安装nginx
    Centos的yum源更换为国内的阿里云源
    配置spotlight连接linux服务器
    linux创建新用户并给予root权限
    linux下安装sar
    liunx中安装禅道
  • 原文地址:https://www.cnblogs.com/anwcq/p/curl_multi.html
Copyright © 2011-2022 走看看