关于Linux使用libcurl对Http请求各层级时间的学习总结和问题记录

仅供作者参考,所得结论不一定正确,欢迎大家进行讨论。

项目上遇到一个问题,在客户端向上传过程中,上传耗时大,造成上传数据积压。无法确定到底是网速问题,还是服务器接收处理时有问题,或者是客户端问题。

这时,我发现libcurl针对获取http客户端发起请求各阶段时间的函数。作者大感喜悦,赶紧将这个函数用到了项目上。然后发现并没有啥用处(-。-)。

先介绍下这个函数,具体信息都来自libcurl官网libcurl - curl_easy_getinfo()

curl_easy_getinfo函数

#include <curl/curl.h>
 CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... );

使用该函数可以在请求求 curl 会话中的相关信息。注意,第 3 个参数必须是一个 long 型,或char型,或curl_slist型,抑或是double型的指针。函数所请求信息只有在函数返回 CURLE_OK 时才会被有效填充,该函数一般用在 perform 函数(如 curl_easy_perform() )之后。

通过这个函数可以传不同的CURLINFO值,获取curl的一些信息。

An overview of the six time values available from curl_easy_getinfo()
 
curl_easy_perform()
    |
    |--NAMELOOKUP
    |--|--CONNECT
    |--|--|--APPCONNECT
    |--|--|--|--PRETRANSFER
    |--|--|--|--|--STARTTRANSFER
    |--|--|--|--|--|--TOTAL
    |--|--|--|--|--|--REDIRECT

Http请求各层级时间参数大致如下:

CURLINFO_NAMELOOKUP_TIME. The time it took from the start until the name resolving was completed.

从开始计算,域名解析完成的耗时

CURLINFO_CONNECT_TIME. The time it took from the start until the connect to the remote host (or proxy) was completed.

从开始计算,TCP建立完成的耗时

CURLINFO_APPCONNECT_TIME. The time it took from the start until the SSL connect/handshake with the remote host was completed. (Added in in 7.19.0)

从开始计算,应用层(SSL,在TCP之上的应用层)连接/握手完成的耗时

CURLINFO_PRETRANSFER_TIME. The time it took from the start until the file transfer is just about to begin. This includes all pre-transfer commands and negotiations that are specific to the particular protocol(s) involved.

从开始计算,准备开始传输数据的耗时

CURLINFO_STARTTRANSFER_TIME. The time it took from the start until the first byte is received by libcurl.

从开始计算,开始传输数据的耗时(libcurl接收到第一个字节)

CURLINFO_TOTAL_TIME. Total time of the previous request.

本次请求的总的耗时

CURLINFO_REDIRECT_TIME. The time it took for all redirection steps include name

lookup, connect, pretransfer and transfer before final transaction was started. So, this is zero if no redirection took place.

整个过程重定向的耗时,如果整个过程没有重定向,这个时间为0,

CURLINFO_SIZE_UPLOAD_TPLOAD

上传速度,经过我个人测试,这个上传速度是包括服务器处理的时间在里面的。

(Deprecated) Average upload speed. See CURLINFO_SPEED_UPLOAD

CURLINFO_SIZE_UPLOAD_T

已上传字节数,个人觉得这个也是个比较重要的参数,如果请求超时,可以看出数据是否传完

CURLINFO_SPEED_DOWNLOAD

下载速度

(Deprecated) Average download speed. See CURLINFO_SPEED_DOWNLOAD

使用示例代码

//部分代码
    code = curl_easy_perform(easy_handle);
	if (nDetailLog)
	{
		g_Log.write_log(1, "Upload info end perform !");
	}
	if (code == CURLE_OK)
	{
		printf("upload infor successfully! \n");

		double namelookuptime = 0;//从开始计算,域名解析完成的耗时
		double connecttime = 0;//从开始计算,TCP建立完成的耗时
		double appconnecttime = 0;//从开始计算,应用层(SSL,在TCP之上的应用层)连接 / 握手完成的耗时
		double pretransfertime = 0;//从开始计算,准备开始传输数据的耗时
		double starttransfertime = 0;//从开始计算,开始传输数据的耗时(libcurl接收到第一个字节)
		double totaltime = 0;//总的耗时
		double redirecttime = 0;//总的耗时


		if (curl_easy_getinfo(easy_handle, CURLINFO_NAMELOOKUP_TIME, &namelookuptime) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_CONNECT_TIME, &connecttime) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_APPCONNECT_TIME, &appconnecttime) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_PRETRANSFER_TIME, &pretransfertime) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_STARTTRANSFER_TIME, &starttransfertime) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_TOTAL_TIME, &totaltime) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_REDIRECT_TIME, &redirecttime) == CURLE_OK
			)
		{
			printf("Uploadinfo Time: namelookuptime:%lf,connecttime:%lf,appconnecttime:%lf,pretransfertime:%lf,starttransfertime:%lf,redirecttime:%lf! \n"
				, namelookuptime, connecttime, appconnecttime, pretransfertime, starttransfertime, redirecttime);
			printf("Uploadinfo Time: transfertime:%lf,handletime:%lf,totaltime:%lf\n"
				, pretransfertime, starttransfertime - pretransfertime, totaltime);

			g_Log.write_log(1, "Uploadinfo Time: namelookuptime:%lf,connecttime:%lf,appconnecttime:%lf,pretransfertime:%lf,starttransfertime:%lf,redirecttime:%lf!  "
				, namelookuptime, connecttime, appconnecttime, pretransfertime, starttransfertime, redirecttime);
			g_Log.write_log(1, "Uploadinfo Time: transfertime:%lf,handletime:%lf,totaltime:%lf"
				, pretransfertime, starttransfertime - pretransfertime, totaltime);
		}

		double speedupload = 0;
		double speeddownload = 0;
		double uploadsize = 0;
		double downloadsize = 0;
		if (curl_easy_getinfo(easy_handle, CURLINFO_SPEED_UPLOAD, &speedupload) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_SPEED_DOWNLOAD, &speeddownload) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_CONTENT_LENGTH_UPLOAD, &uploadsize) == CURLE_OK
			&& curl_easy_getinfo(easy_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &downloadsize) == CURLE_OK
			)
		{
			printf("Uploadinfo Speed: speedupload(bytes/sec):%lf,speeddownload:%lf,uploadsize:%lf,downloadsize:%lf\n"
				, speedupload, speeddownload, uploadsize, downloadsize);
			g_Log.write_log(1, "Uploadinfo Speed: speedupload(bytes/sec):%lf,speeddownload:%lf,uploadsize:%lf,downloadsize:%lf\n"
				, speedupload, speeddownload, uploadsize, downloadsize);
		}
	}

为了能更方便的测试,我将服务器接收端的处理函数做了延时10秒,并且把客户端发送过来的信息保存在本地的处理。

以下是测试结果

2022-05-20 17:18:47.980686 [info]: Upload info start perform 
2022-05-20 17:18:57.984972 [info]: recv_result handle time = 0.000066 
2022-05-20 17:18:57.985067 [info]: Upload info end perform 
2022-05-20 17:18:57.985140 [info]: Uploadinfo Time: namelookuptime:0.000049,connecttime:0.000673,appconnecttime:0.000000,pretransfertime:0.000733,starttransfertime:10.004123,redirecttime:0.000000! 
2022-05-20 17:18:57.985171 [info]: Uploadinfo Time: transfertime:0.000733,handletime:10.003390,totaltime:10.00429
2022-05-20 17:18:57.985211 [info]: Uploadinfo Speed: speedupload(bytes/sec):44.000000,speeddownload:2.000000,uploadsize:442.000000,downloadsize:30.000000

2022-05-20 17:18:57.995446 [info]: Upload Event pic start perform, wait for reply !
2022-05-20 17:19:08.237834 [info]: recv_result handle time = 0.000060 
2022-05-20 17:19:08.237918 [info]: Upload Event pic end perform !
2022-05-20 17:19:08.237966 [info]: Upload Event pic  Time: namelookuptime:0.000045,connecttime:0.000700,appconnecttime:0.000000,pretransfertime:0.000790,starttransfertime:1.002481,redirecttime:0.000000! 
2022-05-20 17:19:08.237993 [info]: Upload Event pic  Time: transfertime:0.000790,handletime:1.001691,totaltime:10.24218
2022-05-20 17:19:08.238027 [info]: Upload Event pic Speed: speedupload(bytes/sec):47768.000000,speeddownload:2.000000,uploadsize:489246.000000,downloadsize:30.000000

2022-05-20 17:19:08.238927 [info]: upload Plate pic start perform 
2022-05-20 17:19:18.518344 [info]: recv_result handle time = 0.000131 
2022-05-20 17:19:18.518529 [info]: upload Plate pic end perform 
2022-05-20 17:19:18.518612 [info]: UploadPlatePic Time: namelookuptime:0.000047,connecttime:0.000761,appconnecttime:0.000000,pretransfertime:0.000878,starttransfertime:1.001508,redirecttime:0.000000! 
2022-05-20 17:19:18.518651 [info]: UploadPlatePic Time: transfertime:0.000878,handletime:1.000630,totaltime:10.27949
2022-05-20 17:19:18.518697 [info]: UploadPlatePic Speed: speedupload(bytes/sec):753.000000,speeddownload:2.000000,uploadsize:7742.000000,downloadsize:30.000000

从这个结果中可以看出,上传信息模块(大小442bytes),这个处理时间是正常的,在10秒多。

但是上传两张图片的信息(大数据,489246bytes和7742bytes),这个处理时间看起来不是我们预想中的时间

个人猜测是因为对于大数据,采用了100-continue的方式进行post的原因。

在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为俩步,

  1. 发送一个请求, 包含一个Expect:100-continue, 询问Server使用愿意接受数据

  2. 接收到Server返回的100-continue应答以后, 才把数据POST给Server 

这是libcurl的行为.

所以,针对大数据包整个请求时间长的问题,暂时还是没有能看出来到底是处理时间长还是网络差造成传输时间长

参考文档:使用CURL检测Clinet侧发起的HTTP请求各阶段时间_H2O's运维&开发路的技术博客_51CTO博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值