一个简单的HTTP并发测试程序

#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define MAX_THREAD 500

static unsigned long long run_time = 0;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

struct HttpStatistics	//计时
{
	unsigned long long requestTime;
	unsigned long long responseTime; 
};

struct HttpGetParam	//参数
{
	char *url;
	struct HttpStatistics httpStatistics;
};

unsigned long long GetCurrentNanoseconds()//当前时间
{
	struct timespec tvTime;
	clock_gettime(CLOCK_REALTIME, &tvTime);
	return (unsigned long long)tvTime.tv_sec * 1000000000ULL + (unsigned long long)tvTime.tv_nsec;
}

static size_t write_data(void *ptr, size_t size, size_t nmemb, void *param)
{
	return size * nmemb;
}

static size_t head_data(void *ptr, size_t size, size_t nmemb, void *param)
{
	struct HttpGetParam *phttpGetParam = (struct HttpGetParam *)param;
	unsigned long long currentTime = 0;
	unsigned long long usedTime = 0;

	if ( phttpGetParam->httpStatistics.responseTime == 0)//只记录第一次收到报文时候的内容
	{
		currentTime = GetCurrentNanoseconds();
		phttpGetParam->httpStatistics.responseTime = currentTime;
		usedTime = currentTime - phttpGetParam->httpStatistics.requestTime;
		//printf("Time is:%llu\n", usedTime/1000000);
		//printf("%s\n", (char*)ptr);
        pthread_mutex_lock(&mutex);
        run_time++;
        pthread_mutex_unlock(&mutex);
	}
	return size * nmemb;
}

//每个线程的处理
void * http_get(void *param)
{
	struct HttpGetParam *phttpGetParam = (struct HttpGetParam *)param;

	CURL *curl;//定义CURL类型的指针
	CURLcode res; //定义CURLcode类型的变量

    //pthread_detach(pthread_self());
	curl = curl_easy_init();//初始化一个CURL类型的指针

	//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);//这里打开libcurl打印所有调试信息

	//curl_easy_setopt(curl, CURLOPT_WRITEDATA, phttpGetParam);
	curl_easy_setopt(curl, CURLOPT_HEADERDATA, phttpGetParam);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); //加上这一句就不会把HTTP Body打出来了。。。
	//curl_easy_setopt(curl, CURLOPT_NOBODY, 1);//CURLOPT_NOBODY只下报文头,不包括数据.但是这里默认是head命令,这里注释掉,则是GET命令
	curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, head_data);

	//设置curl选项. 其中CURLOPT_URL是让用户指定url. argv[1]中存放的命令行传进来的网址
	curl_easy_setopt(curl, CURLOPT_URL, phttpGetParam->url);

	while( 1 )
	{
		phttpGetParam->httpStatistics.requestTime = GetCurrentNanoseconds();
		phttpGetParam->httpStatistics.responseTime = 0;
		//调用curl_easy_perform 执行我们的设置.并进行相关的操作. 在这里只在屏幕上显示出来.
		res = curl_easy_perform(curl);//这里可以用循环实现每个线程内部多次处理
		//printf("res=%d\n", res);
	}
	//清除curl操作.
	curl_easy_cleanup(curl);
	return NULL;
}

int main(int argc, char *argv[])
{
	CURLcode res; //定义CURLcode类型的变量
	pthread_t threads[MAX_THREAD];//PID
	int i, ret;
	struct HttpGetParam httpGetParams[MAX_THREAD];
    pthread_attr_t thread_attr;
    size_t stack_size;

	if (argc !=2)
	{
		printf("Usage : %s <url>;\n", argv[0]);
		exit(1);
	}

	res = curl_global_init(CURL_GLOBAL_ALL);
	if (res != CURLE_OK)
	{
		printf( "Failed to global init default [%d]\n", res );
		return -1;
	} 

	memset(threads, 0, sizeof(threads));
	memset(httpGetParams, 0, sizeof(httpGetParams));

	for ( i = 0; i < MAX_THREAD; i++)
	{
		httpGetParams[i].url = argv[1];
	}
    
    printf("PTHREAD_STACK_MIN=%d\n", PTHREAD_STACK_MIN);
    pthread_attr_init(&thread_attr);
    pthread_attr_getstacksize(&thread_attr, &stack_size);
    printf("Default stack size is %u; minimum is %u\n",
                   stack_size, PTHREAD_STACK_MIN);
    pthread_attr_setstacksize(&thread_attr, 1024 * 1024); //设置线程栈大小,这里设置成了1M,这个可能需要根据情况调,最小不能小于PTHREAD_STACK_MIN,如果太小有可能出现栈溢出
    pthread_attr_getstacksize(&thread_attr, &stack_size);
    printf("New stack size is %u; minimum is %u\n",
                   stack_size, PTHREAD_STACK_MIN);
	for ( i = 0; i < MAX_THREAD; i++)
    {
        //创建线程,threads线程ID
        //ret = pthread_create(&threads[i], NULL, http_get, (void *)&httpGetParams[i]);
        ret = pthread_create(&threads[i], &thread_attr, http_get, (void *)&httpGetParams[i]);
        if (0 != ret)
        {
            perror("pthread_create failed!!! The reason is:");
        }

        if ( (i + 1) % 5 == 0)
        {
            sleep(10);
            printf("Thread num:%d,\tAVG request per second:%llu,\tAVG response time:%f\n", i + 1, run_time/10, 10.0/run_time);
            pthread_mutex_lock(&mutex);
            run_time = 0;
            pthread_mutex_unlock(&mutex);
        }
    }
    pthread_attr_destroy(&thread_attr);

	//sleep(30);
	//等待线程退出
	for ( i = 0; i < MAX_THREAD; i++)
    {
        //判断pthread_t是否有效,解决了段错误问题。
        if (threads[i] != 0)
        {
            pthread_cancel(threads[i]);
            pthread_join(threads[i], NULL);
        }
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值