当前位置:网站首页>基于libco的协程实现6 libcurl的同步接口的实现方案
基于libco的协程实现6 libcurl的同步接口的实现方案
2022-07-17 05:08:00 【HjasnJH】
libcurl:
在c++要发送http/ https请求,我相信很多人会用到libcurl的库,该库的提供了两种接口
curl_easy_perform 阻塞接口
curl_multi_perform 非阻塞接口其中,大多数如果是客户端请求,则一般使用curl_easy_perform接口。
由一些场景,比如,有一个服务,需要接收客户端的请求,然后,统一由服务端像另一个http服务器请求数据,这时候,服务端再使用阻塞接口,则会显示捉襟见肘。

我们通常的做法是要使用libcurl的curl_multi_perform 接口,该接口由几种实现,可以通过select或者poll,但都避免不了,再异步的过程中,我们必须处理消息通信的映射关系,而且有可能你原有的设计,就是通过同步接口多线程的实现方式,这时候,是否由一种方式,不修改为异步的情况下,而不阻塞,这就需要使用协程。
libco是基于线程的,所以,最好如果你的系统使用到第三方的其他库,但是你又不想影响到其他第三方库的运行,那这时候你就需要只在你的那个线程开启协程,也就是说,只有你那个线程会取hook系统调用,这样,你的系统的其他网络库或者第三方库的IO操作,将不会受到任何影响。

libco可以在每个线程中启动,下面我写了个简单的测试程序
int main(int argc, char* argv[])
{
curl_global_init(CURL_GLOBAL_ALL);
ArrayLockFreeQueue<long> vRspList;
ArrayLockFreeQueue<long> vReqList;
std::thread first(TestThread, &vReqList, &vRspList);
int nCnt = 0;
long nReqCount = 0;
while (1)
{
long data;
if (vRspList.try_dequeue(data))
{
printf("GetData from Queue = %d %ld\n", data, GetTickMS());
}
else
{
usleep(1000);
printf("pushData to Queue = %d \n", nReqCount);
vReqList.enqueue(nReqCount++);
}
}
curl_global_cleanup();
return 0;
}其中,定义了两个无锁队列,请求和响应,若想看无锁队列实现,在我的前面文章无锁队列有分享了相关的实现方法。
启动了线程
int EndEventLoop(void* p)
{
return -1;
}
void TestThread(ArrayLockFreeQueue<long>* pReqList, ArrayLockFreeQueue<long>* pRspList)
{
long data = 0;
while (true)
{
if (pReqList->try_dequeue(data))
{
stCoRoutine_t* consumer_routine;
co_create(&consumer_routine, nullptr, Producer, pRspList);
co_resume(consumer_routine);
}
co_eventloop(co_get_epoll_ct(), EndEventLoop, NULL);
}
}不断的从队列拉数据,这里我用到了co_eventloop,但是我不想让它一直在里面循环,导致我取不到队列数据。所以这里腾讯的libco提供了一种返回机制,我用了
然后就是生产者的实现
void* Producer(void* pArgs)
{
co_enable_hook_sys();
CURL* curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
//curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
// curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com/");
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.88.130/");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
long nStart = GetTickMS();
// printf("perform begin %ld\n", nStart);
res = curl_easy_perform(curl);
if (res != 0)
{
static int nErrCount = 0;
printf("curl_ret = %d %d\n", res, ++nErrCount);
}
// printf("perform end ret=%d, %ld\n", res, GetTickMS() - nStart);
curl_easy_cleanup(curl);
if (pArgs)
{
ArrayLockFreeQueue<long>* pList = (ArrayLockFreeQueue<long>*)pArgs;
static int nSend = 0;
// printf("push data to queue %ld\n", GetTickMS());
pList->enqueue(nSend++);
}
}
return NULL;
}
这里我只是简单的将一个数字返回,实际上应用的时候,我们可以返回一个结果集指针,这个都是很灵活的,没有任何限制。
这个代码只是分享大概的逻辑实现。可以做一些修改后应用到真实的环境中。
边栏推荐
猜你喜欢
随机推荐
mysql的锁
热更新及其原理
字幕文件与视频文件对不上的处理方式
Internship project 3- change owner
MapBox 加载本地离线地形
Cesium BIND Mouse Events and remove Mouse Events
Easypoi excel simple export
Cesium bind mouse events and remove mouse events
Wechat applet cloud development and use method-1
Case summary of rotation chart moving speed (constant speed, slow motion)
es6新增-字符串部分
Applet cloud development upload pictures to cloud storage
Installation and fast use of Mongo DB stand-alone version
【AI】利用简单神经网络做动作识别——基于coco关键点
OpenDDS的QoS和自定义QoS(校时TimingQosPolicy)
es6新增-函数部分
微信小程序wx.setClipboardData复制文本
ES6 real case deconstruction (multidimensional array object) new case:
computed和watch的区别
Excel imports long data and changes to 000 at the end









