常用libcurl异步使用方法

目录

1 背景知识
2 libcurl 基础知识
3 libcurl两种模式
4 libcurl实例分析

正文

1 背景知识:

1.1 基本网络通信cs模式,select 框架,网上例子很多.下面只介绍epoll的难点.其他内容请自行搜索.

1.2 epoll 用法

1.2.1 基础知识:

  1. epoll in/out 与socket io 缓冲区关系?
    socket 可读可写是指io 缓冲区的情况,这层由内核控制.socket io 对应的epoll in/out 是应用层.
    epoll 通常采用ET模型.ET触发方式是指当fd到状态发生变化时通知,比如:read buffer从无到有,write buffer从满到不满才会通知.
    所以用while 不停的读,read完缓冲区.下次来数据的时候,缓冲区又是由无到有,又会触发epoll in.
    while 不停的写直到返回缓冲区满返回eagain,然后os立刻会发送,“发送缓冲区的”数据.
    “发送缓冲区的”由满变成不满,再次触发epoll out.进入epoll out分支,开始下一轮while写.
    如果没写满,但是也写完了,不会再次进入epoll out分支.

  2. epoll out的使用时机?

在自己端准备write之前,通过epoll ctrl设置成epoll out.
epoll in 是被动监听接收,epoll out是主动设置.

1.2.2 epoll 模型:网上例子很多.

2 libcurl 基础知识

  1. libcurl作用:它只能做client. 用于文件上传下载和发送http get,post命令.libcurl不是一个简单的api,是一组api实现的模块,有自己的使用steps. 默认curl是get url 网页,与callback write function连动,写入文件。
  2. 两种方案:
    curl_multi_socket_action():通常和select/poll/epoll/libev 连用.
    curl_multi_perform() + curl_multi_wait().

这个是最简单异步,先发送--等待--接收,这种用法很少用了
https://blog.csdn.net/lijinqi1987/article/details/53925835 and https://blog.csdn.net/Rong_Toa/article/details/105712677.
本文讨论curl_multi_socket_action 方案.

3 libcurl两种模式

**3.1 easy 模式(这种模式比较简单) **

调用curl_easy_setopt函数设置传输的一些基本参数,CULROPT_URL必填.设置完成后,调用curl_easy_perform函数发送数据.
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_WRITEDATA, void *pointer);
curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url);
curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, conn);
第一句 curl建立与url 连接,第二句将respond 发送到write_cb,第三句是将write_cb处理内容写入conn指向的文件

3.2 multi 模式

1 ) 常用函数介绍(注意参数)
a ) CURLMOPT_SOCKETFUNCTION:设置socket的回调函数.是所有socket 变化都会调用callback(不仅仅是socket connect,read/write也调用).

int socket_callback(CURL *easy,      /* easy handle */
                    curl_socket_t s, /* socket */
                    int what,        /* describes the socket */
                    void *userp,     /* private callback pointer */
                    void *socketp);  /* private socket pointer */
CURLMOPT_SOCKETDATA: it is params userp

对于接收的话,CURLMOPT_SOCKETDATA没用。socketp是返回值。
CURLMOPT_TIMERDATA and CURLOPT_WRITEDATA 都是对应 curl function的入参.

b) CURLMOPT_TIMERFUNCTION :set callback to receive timeout values

int timer_callback(CURLM *multi,    /* multi handle */
                   long timeout_ms, /* timeout in number of ms */
                   void *userp);    /* private callback pointer */

You can also use the curl_multi_timeout function to poll the value at any given time,
but for an event-based system using the callback is far better than relying on polling the timeout value.
系统超时操作触发callback.
c ) CURLOPT_WRITEFUNCTION:set callback for writing received data

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);

CURLOPT_WRITEDATA:custom pointer passed to the write callback
设置CURLOPT_WRITEFUNCTION的参数4,把参数1 ptr指向的数据拷到参数4 userdata
d ) curl_multi_setopt

CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_TIMERFUNCTION, timer_callback);

CURLMOPT_TIMERDATA:The userp pointer is set with CURLMOPT_TIMERDATA. 入参
curl_multi_setopt is used to tell a libcurl multi handle how to behave.
CURLMOPT_SOCKETFUNCTION,CURLMOPT_SOCKETDATA,CURLMOPT_TIMERFUNCTION,CURLMOPT_TIMERDATA
e) curl_multi_assign

curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd,   void *sockptr);

set association sockfd with sockptr ;curl系统中将sockfd和sockpt结构体绑定

  1. curl_multi_info_read
    Use curl_multi_info_read(3) to figure out which easy handle that completed. 当前只发现这一个功能
    注意这个函数不是read data,而是read info ,具体说就是completed flag,是结束检测函数.
  2. 重点:
CURLMcode curl_multi_socket_action(CURLM * multi_handle,
                                   curl_socket_t sockfd,
                                   int ev_bitmask,
                                   int *running_handles);

执行curl命令.curl_multi_socket_action=curl_multi_perform:reads/writes available data given an action.通知libcurl读写数据
执行curl_multi_add_handle中的东东. 注意参数3ev_bitmask是action.
比如: 设置了CURLMOPT_SOCKETFUNCTION就从server download file.设置CURLMOPT_UPLOAD就是上传file.
CURLOPT_WRITEFUNCTION 就调用CURLOPT_WRITEDATA将download data写入file.

4 curl实例:

curl同时和socket,epoll,file 同时打交道.
curl精华:curl_multi_socket_action可以自动get file from server(CURLOPT_URL) and 自动write file to local(CURLOPT_WRITEFUNCTION)
4.1 curl+ epoll
CURLOPT_URL=connect,CURLMOPT_SOCKETFUNCTION=epoll_ctrl, curl_multi_socket_action=get remote file and write file to local ,epoll=select.


image

实现步骤和时序:

  1. 创建curl multi handle
  2. 当timeout的时候,初始化socket
  3. socket变化触发socekt 回调函数, 设置epoll_ctrl 并且将socket和curl绑定.
  4. epoll_wait调用epoll_out 分支,curl_multi_socket_action执行发送.
  5. epoll_in 调用epoll_in 分支,curl_multi_socket_action执行接收.
  6. curl_multi_info_read 判断是否读完. 读完,删除curl multi handle.
    代码:
epoll_ctl(curl_epoll_fd, EPOLL_CTL_ADD, curl_timer_fd, &ev);//put timer into epoll
curl_easy_setopt(curl, CURLOPT_URL, request_uri);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_read_http_body);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, relay_session);
CURLMcode rc = curl_multi_add_handle(curl_multi, curl);
curl_multi_setopt(curl_multi, CURLMOPT_TIMERFUNCTION, curl_timer_setup);//call back for timer
curl_multi_setopt(curl_multi, CURLMOPT_SOCKETFUNCTION, curl_sock_setup);//socket fd 有变化,会调用curl_sock_setup 
curl_multi_thread  = g_thread_try_new("curl multi thread", &curl_multi_thread_run, NULL, NULL);

static void* curl_multi_thread_run(void* user_data) {
    int i, nfds;
    struct epoll_event *ev = (struct epoll_event *)malloc(sizeof(struct epoll_event) * MAX_EPOLL_FDS_NUM);
    gint64 start_time, end_time;
    while (!janus_is_stopping()) {
        nfds = epoll_wait(curl_epoll_fd, ev, MAX_EPOLL_FDS_NUM, 3000);//wait 3 seconds
        if (nfds > 0) {
            for (i = 0; i < nfds; i++) {
                curl_event(ev[i].data.fd, ev[i].events);//curl_event//curl_event
            }
        }
    }
}
static void curl_event(int fd, int revents) {
    CURLMcode rc;
    int still_running = -1;
    int action = ((revents & EPOLLIN) ? CURL_CSELECT_IN : 0) |
                 ((revents & EPOLLOUT) ? CURL_CSELECT_OUT : 0);
    //call CURLOPT_WRITEFUNCTION callback;read/write curl data
    rc = curl_multi_socket_action(curl_multi, fd, action, &still_running);
    if (rc == CURLM_OK) {
        check_multi_info();//check result
    }
}
static void check_multi_info(void) {
    CURLMsg *msg = NULL;
    int msgs_left;
    CURL *curl = NULL;
    CURLcode res;
    janus_session* session = NULL;
    json_error_t error;
    json_t *root = NULL;
    //从curl msg queue中读取
    while ((msg = curl_multi_info_read(curl_multi, &msgs_left))) {
        curl = msg->easy_handle;
        res = msg->data.result;
        curl_easy_getinfo(curl, CURLINFO_PRIVATE, &session);//it is from CURLOPT_PRIVATE
        curl_multi_remove_handle(curl_multi, curl);
        curl_easy_cleanup(curl);
    }
}

https://curl.haxx.se/libcurl/c/ephiperfifo.html
[https://www.jianshu.com/p/80274bc54aff]
(https://www.jianshu.com/p/80274bc54aff)
https://blog.csdn.net/Rong_Toa/article/details/105712677
https://blog.csdn.net/lijinqi1987/article/details/53996129
https://www.cnblogs.com/zl-graduate/articles/6724446.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容