libcurl异步方式使用总结

原文链接:https://www.cnblogs.com/Newdawn/p/10051231.html

libcurl这个库的同步方式很简单,不做介绍,而异步方式很难理解,本博客参考官网的demo讲解,刚开始看可能很蒙,最后会整合全流程。

使用步骤如下:

1.初始化创建一个multi句柄:

1 CURLM *multi = curl_multi_init();

2.对multi句柄设置socket回调和timer回调:

1 curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, multi_sock_cb);
2 curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, &param);
3 curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
4 curl_multi_setopt(multi, CURLMOPT_TIMERDATA, &param);

3.对multi句柄添加easy句柄,异步开始:

1 CURL *easy = curl_easy_init();
2 curl_easy_setopt(conn->easy, CURLOPT_URL, url);
3 curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb);  // 负责读入数据的函数
4 curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, &data);
5 curl_multi_add_handle(multi, easy);

先看看第三行设置的write_cb,该函数是你读入数据的函数:

1 /*
2  * ptr 指向libcurl库读到的数据
3  * data 用户自定义的缓冲区, 上面第四行设置
4  */
5 size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data) {
6     // 把ptr指向的数据拷到data
7 }

curl_multi_add_handle运行结束的那一刻,第2步设置的multi_timer_cb马上被拉起执行,让我们看看multi_timer_cb的函数声明:

1 /* 
2  * multi 第一步创建的句柄
3  * timeout_ms libcurl库维护的一个超时时间,具体怎么算不清楚,回调时会自动赋值
4  * param 第二步设置的参数
5  * return 错误码
6  */
7 int multi_timer_cb(CURLM *multi, long timeout_ms, void *param)

libcurl库本身没有定时器功能,只是告诉你一个定时时间timeout_ms,这就要求我们自己维护一个定时器和到期的回调函数timer_cb。 
伪代码表示如下:

1 int multi_timer_cb(CURLM *multi, long timeout_ms, void *param) {
2     timer_.add(timer_cb, ms);  // ms后执行timer_cb
3 }

timer_cb主要调用libcurl的两个函数:

 1 void timer_cb(param...) {
 2   CURLMcode rc;
 3   rc = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
 4                                 &still_running);
 5   while((msg = curl_multi_info_read(multi, &msgs_left))) {   // 判断数据是否读完
 6     if(msg->msg == CURLMSG_DONE) {
 7         // 清理资源操作
 8     }
 9   }
10 }

multi_sock_cb类似如此:

1 /*
2  * e 第三步添加的easy句柄
3  * s libcurl创建维护的socket
4  * what 执行动作(读或写)
5  */
6 int multi_sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)

在libcurl维护的socket描述符发生状态改变时(变回可读或可写),multi_sock_cb才会被回调。注意,函数回调时,第二个参数是socket描述符,这是libcurl维护创建的,但是你把它添加到poller(代指epoll或poll的封装类)或者libev等事件触发器中去,并设置回调函数,伪代码如下

1 int multi_sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) {
2     poller.add(s, socket_cb);  // 当描述符可读和可写时,调用socket_cb
3 }

看到这里是不是懵逼,不要急,最后会讲解全流程。socket_cb里也是调用两个libcurl函数:

 1 void socket_cb(param...) {
 2   CURLMcode rc;
 3   rc = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
 4                                 &still_running);
 5   while((msg = curl_multi_info_read(multi, &msgs_left))) {   // 判断数据是否读完
 6     if(msg->msg == CURLMSG_DONE) {
 7         // 清理资源操作
 8         }
 9     }
10 }

好了,函数写成这样就差不多了(都是伪代码,具体用法还是看demo)。那么这代码到底是怎么执行的呢,请看下图。

1、在curl_multi_add_handle之后,multi_timer_cb会马上被拉起调用,然后第一次调用的话timeout是0ms,所以timer_cb也会被拉起,然后调用curl_multi_socket_action。

2、此时,请注意在curl_multi_add_handle之前已经设置过了url了,所以此时是需要发起http请求,即写请求,所以在curl_multi_socket_action中libcurl会创建一个socket描述符,然后状态变为可写。

3、此时,因为libcurl的socket描述符状态发生改变,所以multi_sock_cb会被拉起,multi_sock_cb中就把socket描述符添加到poller中,设置写事件的回调函数为socket_cb。

4、因为socket描述符是可写的,所以poller会调用sock_cb,curl_multi_socket_action又被调用,而此函数就会发送http请求(即libcurl负责写fd)。

5、等到http请求被发送完,就需要接收响应,所以libcurl会把socket描述符从写状态改为读状态。

6、因为socket描述符变为可读,状态改变,multi_sock_cb又被调用,此时在poller中,将socket描述符的读事件回调函数设置为socket_cb。

7、当响应到来的时候,socket描述符可读,调用socket_cb,从而调用curl_multi_socket_action,该函数就就会异步调用之前设置的、负责读入数据的write_cb,从而读入数据。

8、 不断重复上一个步骤,直到数据被读完,此时libcurl会把socket描述符设置为删除状态,所以multi_sock_cb会被回调,负责清理资源。而且,curl_multi_info_read会判断已经读完数据,可以在这里进行数据转发,最终进行资源清理。注意,最终读到的数据,会在write_cb设置的data中(前提是你有在write_cb中保存下来哈哈哈~)。

总结:
这库使用起来十分奇怪,我看了几天才看懂用法,我这篇博文写得十分简陋,最好的学习方法还是把demo跑一遍,看看打印出来的日志,还有详细的参数设置,需要去看官网文档。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
libcurl 是一个常用的用于网络传输的 C 函数库,它支持各种网络协议和通信方式,包括 HTTP、FTP、SMTP 等,并且可以实现异步长连接访问。 异步访问是指在进行网络请求的同时,程序可以继续执行其他操作,不需要等待请求完成再进行下一步操作。而长连接是指在一次建立连接后,可以多次发送请求,不需要每次都重新建立连接。 在 libcurl 中,可以通过设置 CURLMOPT_PIPELINING 选项来开启长连接,然后通过设置 curl_easy_setopt 函数的 CURLMOPT_CHUNK_LENGTH 和 CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE 选项来调整请求的长度和延迟等参数。 同时,libcurl 还提供了 multi interface,通过这个接口可以在多个请求之间切换,实现异步访问。具体方法是先通过 curl_multi_init 函数初始化一个 multi 对象,然后使用 curl_easy_setopt 函数设置每个请求的参数,最后通过 curl_multi_add_handle 函数将请求添加到 multi 对象中。通过 curl_multi_perform 函数可以开始异步访问,然后通过 curl_multi_fdset 和 curl_multi_wait 函数来等待请求完成,最后通过 curl_multi_remove_handle 函数将请求从 multi 对象中删除。 libcurl 异步长连接访问的主要优势在于可以提高程序的并发能力和效率,减少网络请求的开销和资源消耗。但需要注意的是,由于异步访问可能会带来线程安全等问题,因此在使用时需要注意保护资源和数据的完整性和安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值