multi接口的使用会比easy 接口稍微复杂点,毕竟multi接口是依赖easy接口的,首先粗略的讲下其使用流程:curl_multi _init初始化一个multi curl对象,为了同时进行多个curl的并发访问,我们需要初始化多个easy curl对象,使用curl_easy_setopt进行相关设置,然后调用curl_multi _add_handle把easy curl对象添加到multi curl对象中,添加完毕后执行curl_multi_perform方法进行并发的访问,访问结束后curl_multi_remove_handle移除相关easy curl对象,curl_easy_cleanup清除easy curl对象,最后curl_multi_cleanup清除multi curl对象。

#include <string>
#include <iostream>

#include <curl/curl.h>
#include <sys/time.h>
#include <unistd.h>

using namespace std;

size_t curl_writer(void *buffer, size_t size, size_t count, void * stream)
{
    std::string * pStream = static_cast<std::string *>(stream);
    (*pStream).append((char *)buffer, size * count);

    return size * count;
};

/**
 * 生成一个easy curl对象,进行一些简单的设置操作
 */
CURL * curl_easy_handler(const std::string & sUrl,
                         const std::string & sProxy,
                         std::string & sRsp,
                         unsigned int uiTimeout)
{
    CURL * curl = curl_easy_init();

    curl_easy_setopt(curl, CURLOPT_URL, sUrl.c_str());
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, );

    )
    {
        curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, uiTimeout);
    }
    if (!sProxy.empty())
    {
        curl_easy_setopt(curl, CURLOPT_PROXY, sProxy.c_str());
    }

    // write function //
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_writer);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &sRsp);

    return curl;
}

/**
 * 使用select函数监听multi curl文件描述符的状态
 * 监听成功返回0,监听失败返回-1
 */
int curl_multi_select(CURLM * curl_m)
{
    ;

    struct timeval timeout_tv;
    fd_set  fd_read;
    fd_set  fd_write;
    fd_set  fd_except;
    ;

    // 注意这里一定要清空fdset,curl_multi_fdset不会执行fdset的清空操作  //
    FD_ZERO(&fd_read);
    FD_ZERO(&fd_write);
    FD_ZERO(&fd_except);

    // 设置select超时时间  //
    timeout_tv.tv_sec = ;
    timeout_tv.tv_usec = ;

    // 获取multi curl需要监听的文件描述符集合 fd_set //
    curl_multi_fdset(curl_m, &fd_read, &fd_write, &fd_except, &max_fd);

    /**
     * When max_fd returns with -1,
     * you need to wait a while and then proceed and call curl_multi_perform anyway.
     * How long to wait? I would suggest 100 milliseconds at least,
     * but you may want to test it out in your own particular conditions to find a suitable value.
     */
     == max_fd)
    {
        ;
    }

    /**
     * 执行监听,当文件描述符状态发生改变的时候返回
     * 返回0,程序调用curl_multi_perform通知curl执行相应操作
     * 返回-1,表示select错误
     * 注意:即使select超时也需要返回0,具体可以去官网看文档说明
     */
    , &fd_read, &fd_write, &fd_except, &timeout_tv);
    switch(ret_code)
    {
    :
        /* select error */
        ret = -;
        break;
    :
        /* select timeout */
    default:
        /* one or more of curl's file descriptors say there's data to read or write*/
        ret = ;
        break;
    }

    return ret;
}

#define MULTI_CURL_NUM 3

// 这里设置你需要访问的url //
std::string     URL     = "http://website.com";
// 这里设置代理ip和端口  //
std::string     PROXY   = "ip:port";
// 这里设置超时时间  //
unsigned ; /* ms */

/**
 * multi curl使用demo
 */
int curl_multi_demo(int num)
{
    // 初始化一个multi curl 对象 //
    CURLM * curl_m = curl_multi_init();

    std::string     RspArray[num];
    CURL *          CurlArray[num];

    // 设置easy curl对象并添加到multi curl对象中  //
    ; idx < num; ++idx)
    {
        CurlArray[idx] = NULL;
        CurlArray[idx] = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);
        if (CurlArray[idx] == NULL)
        {
            ;
        }
        curl_multi_add_handle(curl_m, CurlArray[idx]);
    }

    /*
     * 调用curl_multi_perform函数执行curl请求
     * url_multi_perform返回CURLM_CALL_MULTI_PERFORM时,表示需要继续调用该函数直到返回值不是CURLM_CALL_MULTI_PERFORM为止
     * running_handles变量返回正在处理的easy curl数量,running_handles为0表示当前没有正在执行的curl请求
     */
    int running_handles;
    while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))
    {
        cout << running_handles << endl;
    }

    /**
     * 为了避免循环调用curl_multi_perform产生的cpu持续占用的问题,采用select来监听文件描述符
     */
    while (running_handles)
    {
         == curl_multi_select(curl_m))
        {
            cerr << "select error" << endl;
            break;
        } else {
            // select监听到事件,调用curl_multi_perform通知curl执行相应的操作 //
            while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl_m, &running_handles))
            {
                cout << "select: " << running_handles << endl;
            }
        }
        cout << "select: " << running_handles << endl;
    }

    // 输出执行结果 //
    int         msgs_left;
    CURLMsg *   msg;
    while((msg = curl_multi_info_read(curl_m, &msgs_left)))
    {
        if (CURLMSG_DONE == msg->msg)
        {
            int idx;
            ; idx < num; ++idx)
            {
                if (msg->easy_handle == CurlArray[idx]) break;
            }

            if (idx == num)
            {
                cerr << "curl not found" << endl;
            } else
            {
                cout << "curl [" << idx << "] completed with status: "
                        << msg->data.result << endl;
                cout << "rsp: " << RspArray[idx] << endl;
            }
        }
    }

    // 这里要注意cleanup的顺序 //
    ; idx < num; ++idx)
    {
        curl_multi_remove_handle(curl_m, CurlArray[idx]);
    }

    ; idx < num; ++idx)
    {
        curl_easy_cleanup(CurlArray[idx]);
    }

    curl_multi_cleanup(curl_m);

    ;
}

/**
 * easy curl使用demo
 */
int curl_easy_demo(int num)
{
    std::string     RspArray[num];

    ; idx < num; ++idx)
    {
        CURL * curl = curl_easy_handler(URL, PROXY, RspArray[idx], TIMEOUT);
        CURLcode code = curl_easy_perform(curl);
        cout << "curl [" << idx << "] completed with status: "
                << code << endl;
        cout << "rsp: " << RspArray[idx] << endl;

        // clear handle //
        curl_easy_cleanup(curl);
    }

    ;
}

#define USE_MULTI_CURL

struct timeval begin_tv, end_tv;

int main(int argc, char * argv[])
{
    )
    {
        ;
    }
    ]);

    // 获取开始时间 //
    gettimeofday(&begin_tv, NULL);
#ifdef USE_MULTI_CURL
    // 使用multi接口进行访问 //
    curl_multi_demo(num);
#else
    // 使用easy接口进行访问 //
    curl_easy_demo(num);
#endif
    // 获取结束时间  //
    struct timeval end_tv;
    gettimeofday(&end_tv, NULL);

    // 计算执行延时并输出,用于比较  //
     +
                   (end_tv.tv_usec - begin_tv.tv_usec) / ;

    cout << "eclapsed time:" << eclapsed << "ms" << endl;

    ;
}

转载自: http://blog.csdn.net/zxgfa/article/details/8220724

c语言libcurl库的异步用法的更多相关文章

  1. 转载~kxcfzyk:Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解

    Linux C语言多线程库Pthread中条件变量的的正确用法逐步详解   多线程c语言linuxsemaphore条件变量 (本文的读者定位是了解Pthread常用多线程API和Pthread互斥锁 ...

  2. C语言 HTTP上传文件-利用libcurl库上传文件

    原文  http://justwinit.cn/post/7626/ 通常情况下,一般很少使用C语言来直接上传文件,但是遇到使用C语言编程实现文件上传时,该怎么做呢? 借助开源的libcurl库,我们 ...

  3. Standard C 语言标准函数库介绍

    全面巩固所知所学,往精通方向迈进! Standard C 语言标准函数库速查 (Cheat Sheet) from:http://ganquan.info/standard-c/function/ C ...

  4. C++ 用libcurl库进行http通讯网络编程

    使用libcurl完成http通讯,很方便而且是线程安全,转载一篇比较好的入门文章 转载自 http://www.cnblogs.com/moodlxs/archive/2012/10/15/2724 ...

  5. C++ 用libcurl库进行http通讯网络编程(转)

    转载:http://www.cnblogs.com/moodlxs/archive/2012/10/15/2724318.html 目录索引: 一.LibCurl基本编程框架 二.一些基本的函数 三. ...

  6. Cocos2d-x移植到WindowsPhone8移植问题-libcurl库移植问题

    在Cocos2d-x 3.x最新版本中提供了Windows Phone 8平台移植libcurl库所需要的头文件和库文件.但要在Windows Phone 8平台成功移植libcurl库还是很不容易, ...

  7. Cocos开发中Visual Studio下libcurl库开发环境设置

    我们介绍一下win32中Visual Studio下libcurl库开发环境设置.Cocos2d-x引擎其实已经带有为Win32下访问libcurl库,Cocos2d-x 3.x中libcurl库文件 ...

  8. C++ 用libcurl库进行http通讯网络编程[转]

    http://www.cnblogs.com/moodlxs/archive/2012/10/15/2724318.html 目录索引: 一.LibCurl基本编程框架 二.一些基本的函数 三.cur ...

  9. C/C++ 用libcurl库进行http通讯网络编程

    C/C++ 用libcurl库进行http通讯网络编程 目录索引: 一.LibCurl基本编程框架 二.一些基本的函数 三.curl_easy_setopt函数部分选项介绍 四.curl_easy_p ...

随机推荐

  1. Android 使用代码主动去调用控件的点击事件(模拟人手去触摸控件)

    使用代码主动去调用控件的点击事件(模拟人手去触摸控件) //View 可以是LinearLayout,Button,TextView View.performClick();

  2. android视频播放器

    RTSP(Real Time Streaming Protocol),RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议,由哥伦比亚大学.网景和RealNetworks公司提交的 ...

  3. Perl语言

    Perl是高级.通用.直译式.动态的程序语言家族.最初设计者拉里·沃尔(Larry Wall)为了让在UNIX上进行报表处理的工作变得更方便,决定开发一个通用的脚本语言,而在1987年12月18日发表 ...

  4. Unix环境链接静态库

    静态库 请点评 有时候需要把一组代码编译成一个库,这个库在很多项目中都要用到,例如libc就是这样一个库,我们在不同的程序中都会用到libc中的库函数(例如printf),也会用到libc中的变量(例 ...

  5. C++学习笔记之继承

    一.基类和派生类 很多时候,一个类的对象也“是”另一个类的对象,如矩形是四边形,在C++中,矩形类Rectangle可以由四边形类Quad继承而来,于是,四边形类Quad是基类,矩形类Rectangl ...

  6. oracle 11g在安装过程中出现监听程序未启动或数据库服务未注册到该监听程序

    15511477451 原文 oracle 11g在安装过程中出现监听程序未启动或数据库服务未注册到该监听程序? 环境:win7 64位系统.oracle11g数据库 问题描述:在win7 64位系统 ...

  7. HW4.36

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...

  8. (转)tar 解压缩命令

    tar -c: 建立压缩档案-x:解压-t:查看内容-r:向压缩归档文件末尾追加文件-u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中一个.下面的 ...

  9. IIS发布问题-用户 &#39;IIS APPPOOL\DefaultAppPool&#39; 登录失败

    今天新建了一个ASP.NET(Language=C#)网站,配置好数据库后编写了几行代码测试数据库的是否能正常使用. 当运行程序时,第一个页面都没有打开就出现了错误(因为我首页就访问数据库,填充一些D ...

  10. BZOJ 1123: [POI2008]BLO( tarjan )

    tarjan找割点..不是割点答案就是(N-1)*2, 是割点的话就在tarjan的时候顺便统计一下 ------------------------------------------------- ...