栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

基于libco的协程实现6 libcurl的同步接口的实现方案

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于libco的协程实现6 libcurl的同步接口的实现方案

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 vRspList;
	ArrayLockFreeQueue 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 %ldn", 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* pReqList, ArrayLockFreeQueue* 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 %ldn", nStart);
		res = curl_easy_perform(curl);
		if (res != 0)
		{
			static int nErrCount = 0;
			printf("curl_ret = %d %dn", res, ++nErrCount);
		}
		// printf("perform end ret=%d, %ldn", res, GetTickMS() - nStart);
		curl_easy_cleanup(curl);

		if (pArgs)
		{
			ArrayLockFreeQueue* pList = (ArrayLockFreeQueue*)pArgs;
			static int nSend = 0;
			// printf("push data to queue %ldn", GetTickMS());
			pList->enqueue(nSend++);
		}
	}

	return NULL;
}

这里我只是简单的将一个数字返回,实际上应用的时候,我们可以返回一个结果集指针,这个都是很灵活的,没有任何限制。

这个代码只是分享大概的逻辑实现。可以做一些修改后应用到真实的环境中。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/982620.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号