基于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<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;
}

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值