speedtest依赖的库包括:curl、expat
curl库下载地址:https://curl.haxx.se/download.html
expat库下载地址:https://github.com/libexpat/libexpat(https://github.com/libexpat/libexpat/releases/tag/R_2_2_10)
移植curl库:
复制代码
tar -xvf curl-7.74.0.tar.gz
cd curl-7.74.0
./configure --prefix=XXX/XXX/curl-arm CC=/XXX/XXX/arm-linux-gnueabihf-gcc CXX=/XXX/XXX/arm-linux-gnueabihf-g++ --host=arm-linux
make -j8
make install
#disable TLS with --without-ssl
--with-openssl
--with-amissl
--with-bearssl
--with-gnutls
--with-mbedtls
--with-mesalink
--with-nss
--with-openssl (also works for BoringSSL and libressl)
--with-rustls
--with-schannel
--with-secure-transport
--with-wolfssl
复制代码
其中XXX/XXX/curl-arm目录的include、lib目录就是所需的文件
移植expat库:
tar -xvf expat-2.2.10.tar.bz2
cd expat-2.2.10
./configure --prefix=XXX/XXX/expat-arm CC=/XXX/XXX/arm-linux-gnueabihf-gcc CXX=/XXX/XXX/arm-linux-gnueabihf-g++ --host=arm-linux make -j8 make install
其中XXX/XXX/expat-arm目录的include、lib目录就是所需的文件
编译speedtest程序用于测速
speedtest程序源码:
复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <float.h>
#include <math.h>
#include <curl/curl.h>
#include "expat.h"
#define URL_LENGTH_MAX 255
#define THREAD_NUM_MAX 10
#define UPLOAD_EXT_LENGTH_MAX 5
#define SPEEDTEST_TIME_MAX 10
#define CUNTRY_NAME_MAX 64
#define UPLOAD_EXTENSION_TAG "upload_extension"
#define LATENCY_TXT_URL "/speedtest/latency.txt"
#define INIT_DOWNLOAD_FILE_RESOLUTION 750
#define FILE_350_SIZE 245388
#define MAX_ISP_NAME 255
#define MAX_IPADDRESS_STRLEN 48
#define MAX_CLOSEST_SERVER_NUM 5
#define RECORED_EVERY_SEC 0.2
#define PRINT_RECORED_NUM 2
#define PI 3.1415926
#define EARTH_RADIUS 6378.137
#define UPLOAD_CHRUNK_SIZE_MAX 512000 // Max upload chunk size 512K
#define OK 0
#define NOK 1
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
struct thread_para
{
pthread_t tid;
char url[URL_LENGTH_MAX + 32];
long result;
long upload_size;
long chunk_size;
double now;
char finish;
pthread_mutex_t lock;
};
struct web_buffer
{
char *data;
int size;
};
struct client_info
{
char ip[MAX_IPADDRESS_STRLEN];
double lat;
double lon;
char isp[MAX_ISP_NAME];
};
struct server_info
{
char url[URL_LENGTH_MAX];
double lat;
double lon;
char country[CUNTRY_NAME_MAX];
int id;
double distance;
};
int depth;
struct client_info client;
struct server_info servers[MAX_CLOSEST_SERVER_NUM];
static int show_usage(char* argv[])
{
printf("%s:\n\t\t -p number of threads\n" "\t\t -l list all valid server\n" "\t\t -s specify mini ookla server url\n", argv[0]);
exit(0);
}
static int calc_past_time(struct timeval* start, struct timeval* end)
{
return (end->tv_sec - start->tv_sec) * 1000 + (end->tv_usec - start->tv_usec)/1000;
}
static size_t write_data(void* ptr, size_t size, size_t nmemb, void *stream)
{
struct thread_para *p_thread = (struct thread_para*)stream;
if (p_thread) {
//p_thread->data++;
pthread_mutex_lock(&p_thread->lock);
p_thread->now += size * nmemb;
pthread_mutex_unlock(&p_thread->lock);
}
return size * nmemb;
}
#if 1
void *myrealloc(void *ptr, size_t size)
{
/* There might be a realloc() out there that doesn't like reallocing
NULL pointers, so we take care of it here */
if(ptr)
return realloc(ptr, size);
else
return malloc(size);
}
size_t
write_web_buf(void *ptr, size_t size, size_t nmemb, void *data)
{
size_t realsize = size * nmemb;
struct web_buffer *mem = (struct web_buffer *)data;
mem->data = (char *)realloc(mem->data, mem->size + realsize + 1);
if (mem->data) {
memcpy(&(mem->data[mem->size]), ptr, realsize);
mem->size += realsize;
mem->data[mem->size] = 0;
}
return realsize;
}
#else
static size_t write_web_buf(void* ptr, size_t size, size_t nmemb, void *data)
{
struct web_buffer* buf = (struct web_buffer*)data;
char *p = NULL;
int length = buf->size + size*nmemb + 1;
//printf("le = %p %p %d %d %d\n", p, buf->data, length, size*nmemb, buf->size);
p = (char*)realloc(buf->data, buf->size + size*nmemb + 1);
if (p == NULL) {
printf("realloc failed\n");
return 0;
}
buf->data = p;
memcpy(&buf->data[buf->size], ptr, size*nmemb);
buf->size += size * nmemb;
buf->data[buf->size] = 0;
return size * nmemb;
}
#endif
double radian(double d)
{
return d * PI / 180.0;
}
double get_distance(double lat1, double lng1, double lat2, double lng2)
{
double radLat1 = radian(lat1);
double radLat2 = radian(lat2);
double a = radLat1 - radLat2;
double b = radian(lng1) - radian(lng2);
double dst = 2 * asin((sqrt(pow(sin(a / 2), 2) + cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2) )));
dst = dst * EARTH_RADIUS;
dst= round(dst * 10000) / 10000;
return dst;
}
static void XMLCALL start_element(void *userData, const char *el, const char **atts)
{
int i;
if (depth == 1 && strcmp(el, "client") == 0) {
struct client_info *p_client = (struct client_info *)userData;
for (i = 0; atts[i]; i += 2) {
//printf(" %s \n", atts[i]);
if (strcmp(atts[i], "ip") == 0)
strcpy(p_client->ip, atts[i + 1]);
if (strcmp(atts[i], "isp") == 0)
strcpy(p_client->isp, atts[i + 1]);
if (strcmp(atts[i], "lat") == 0)
p_client->lat = atof(atts[i + 1]);
if (strcmp(atts[i], "lon") == 0)
p_client->lon = atof(atts[i + 1]);
//printf("client %s %s %lf %lf\n", p_client->ip, p_client->isp, p_client->lat, p_client->lon);
}
}
if (depth == 2 && strcmp(el, "server") == 0) {
struct server_info *p_server = (struct server_info *)userData;
for (i = 0; atts[i]; i += 2) {
//printf(" %s \n", atts[i]);
if (strcmp(atts[i], "url") == 0)
strcpy(p_server->url, atts[i + 1]);
if (strcmp(atts[i], "country") == 0)
strcpy(p_server->country, atts[i + 1]);
if (strcmp(atts[i], "lat") == 0)
p_server->lat = atof(atts[i + 1]);
if (strcmp(atts[i], "lon") == 0)
p_server->lon = atof(atts[i + 1]);
if (strcmp(atts[i], "id") == 0)
p_server->id = atof(atts[i + 1]);
}
}
depth++;
}
static void XMLCALL end_element(void *userData, const char *name)
{
depth--;
if (strcmp(name, "server") == 0) {
int i;
struct server_info *p_server = (struct server_info *)userData;
p_server->distance = get_distance(client.lat, client.lon, p_server->lat, p_server->lon);
for (i = 0; i < MAX_CLOSEST_SERVER_NUM; i++) {
if ( servers[i].url[0] == 0 ) {
break;
}
}
if ( i == MAX_CLOSEST_SERVER_NUM ) {
for (i = 0; i <MAX_CLOSEST_SERVER_NUM; i++) {
if (servers[i].distance > p_server->distance) {
break;
}
}
}
if (i != MAX_CLOSEST_SERVER_NUM)
memcpy(&servers[i], p_server, sizeof(struct server_info));
memset(p_server, 0, sizeof(struct server_info));
}
}
static int do_latency(char *p_url)
{
char latency_url[URL_LENGTH_MAX + sizeof(LATENCY_TXT_URL)] = {0};
CURL *curl;
CURLcode res;
long response_code;
curl = curl_easy_init();
sprintf(latency_url, "%s%s", p_url, LATENCY_TXT_URL);
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "User-Agent: curl/7.67.0");
curl_easy_setopt(curl, CURLOPT_URL, latency_url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3L);
res = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
curl_easy_cleanup(curl);
if (res != CURLE_OK || response_code != 200) {
//printf("curl_easy_perform() failed: %s %ld\n", curl_easy_strerror(res), response_code);
return NOK;
}
return OK;
}
static double test_latency(char *p_url)
{
struct timeval s_time, e_time;
double latency;
gettimeofday(&s_time, NULL);
if (do_latency(p_url) != OK)
return DBL_MAX;
gettimeofday(&e_time, NULL);
latency = calc_past_time(&s_time, &e_time);
return latency;
}
static void* do_download(void* data)
{
CURL *curl;
CURLcode res;
struct thread_para* p_para = (struct thread_para*)data;
double length = 0;
double time = 0, time1 = 0, time2;
curl = curl_easy_init();
//printf("image url = %s\n", p_para->url);
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "User-Agent: curl/7.67.0");
curl_easy_setopt(curl, CURLOPT_URL, p_para->url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, p_para);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return NULL;
}
curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &length);
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &time);
curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time1);
curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time2);
//printf("Length is %lf %lf %lf %lf\n", length, time, time1, time2);
p_para->result = length;
p_para->finish = 1;
curl_easy_cleanup(curl);
return NULL;
}
static void loop_threads(struct thread_para *p_thread, int num_thread, double *speed, int *p_num_speed)
{
char alive = 0;
int num = 0, num_speed = 0;
do {
int i, time = 0;
double sum = 0;
alive = 0;
for (i = 0;i < num_thread; i++) {
if (p_thread[i].finish == 0)
alive = 1;
pthread_mutex_lock(&p_thread->lock);
sum += p_thread[i].now;
p_thread[i].now = 0;
pthread_mutex_unlock(&p_thread->lock);
//printf("p_thread[i].now = %lf\n", p_thread[i].now);
}
usleep(RECORED_EVERY_SEC*1000*1000); //0.2s
if (sum == 0 && num_speed == 0)
continue;
if (num_speed < *p_num_speed) {
speed[num_speed] = sum/RECORED_EVERY_SEC; //Byte
num_speed++;
}
if (++num % PRINT_RECORED_NUM == 0) {
printf(".");
fflush(stdout);
}
}while(alive);
printf("\n");
*p_num_speed = num_speed;
return;
}
static double calculate_average_speed(double *p_speed, int num_speed)
{
int i = 0;
int start ,end;
double sum = 0;
for (i = 0; i < num_speed; i++) {
int j, min;
for ( min = i, j = i + 1; j < num_speed; j++) {
if (p_speed[min] > p_speed[j])
min = j;
}
if (min != i) {
double tmp;
tmp = p_speed[i];
p_speed[i] = p_speed[min];
p_speed[min] = tmp;
}
}
#if 0
for (i = 0; i < num_speed; i++) {
printf("%0.2lf ", p_speed[i]*8/(1024*1024));
if (i%10 == 0)
printf("\n");
}
#endif
/*The fastest 10% and slowest 20% of the slices are discarded*/
start = num_speed*0.2;
end = num_speed - (int)(num_speed*0.1);
//end = num_speed;
for (i = start; i < end; i++) {
sum += p_speed[i];
}
//printf("speed = %0.2lf\n", (sum*8/(end - start))/(1024*1024));
return sum/(end - start);
}
static int init_instant_speed(double **p_speed, int *p_speed_num)
{
*p_speed_num = SPEEDTEST_TIME_MAX/RECORED_EVERY_SEC + 1;
*p_speed = (double*)malloc((*p_speed_num)*sizeof(double));
if (*p_speed == NULL) {
fprintf(stderr, "malloc failed\n");
return -1;
}
memset(*p_speed, 0, (*p_speed_num)*sizeof(double));
return 0;
}
static int test_download(char *p_url, int num_thread, int dsize, char init)
{
struct timeval s_time;
int time, i, error;
struct thread_para paras[THREAD_NUM_MAX];
double sum = 0;
double speed = 0;
double *instant_speed = NULL;
int speed_num = 0;
gettimeofday(&s_time, NULL);
init_instant_speed(&instant_speed, &speed_num);
for ( i = 0; i < num_thread; i++) {
memset(¶s[i], 0, sizeof(struct thread_para));
sprintf(paras[i].url, "%s/speedtest/random%dx%d.jpg", p_url, dsize, dsize);
paras[i].result = 0;
error = pthread_create(¶s[i].tid, NULL, do_download, (void*)¶s[i]);
if ( error != 0)
printf("Can't Run thread num %d, error %d\n", i, error);
}
if (init != 0)
{
loop_threads(paras, num_thread, instant_speed, &speed_num);
}
for (i = 0;i < num_thread; i++) {
pthread_join(paras[i].tid, NULL);
sum += paras[i].result;
}
if (init != 0) {
speed = calculate_average_speed(instant_speed, speed_num);
}else {
struct timeval e_time;
gettimeofday(&e_time, NULL);
time = calc_past_time(&s_time, &e_time);
speed = (sum*1000)/time;
//printf("msec = %d speed = %0.2fMbps\n", time, ((sum*8*1000/time))/(1024*1024));
}
free(instant_speed);
return speed;
}
static size_t read_data(void* ptr, size_t size, size_t nmemb, void *userp)
{
struct thread_para* para = (struct thread_para*)userp;
int length;
char data[16284] = {0};
if (size * nmemb < 1 && para->chunk_size)
return 0;
int i;
for (i = 0; i < 16284; i++) {
data[i] = i%26 + 'a';
}
if (para->chunk_size > size * nmemb) {
length = size * nmemb < 16284 ? size*nmemb : 16284;
}
else
length = para->chunk_size < 16284 ? para->chunk_size : 16284;
memcpy(ptr, data, length);
para->chunk_size -= length;
pthread_mutex_lock(¶->lock);
para->now += length;
pthread_mutex_unlock(¶->lock);
//printf("length = %d\n", length);
return length;
}
static int do_upload(struct thread_para* para)
{
CURL *curl;
CURLcode res;
long size = para->upload_size;
int loop = 1;
if (size > UPLOAD_CHRUNK_SIZE_MAX)
loop = (size / UPLOAD_CHRUNK_SIZE_MAX) + 1;
curl = curl_easy_init();
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "User-Agent: curl/7.67.0");
curl_easy_setopt(curl, CURLOPT_URL, para->url);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data);
curl_easy_setopt(curl, CURLOPT_READDATA, para);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
while (loop) {
double size_upload;
para->chunk_size = size - para->result> UPLOAD_CHRUNK_SIZE_MAX ?
UPLOAD_CHRUNK_SIZE_MAX : size - para->result;
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE , (curl_off_t)para->chunk_size);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "Error: curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
para->finish = 1;
return NOK;
}
curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &size_upload);
para->result += size_upload;
loop--;
}
curl_easy_cleanup(curl);
para->finish = 1;
//printf("size upload = %lf\n", size_upload);
return OK;
}
static int test_upload(char *p_url, int num_thread, long size, char *p_ext, char init)
{
struct timeval s_time;
int i, error;
struct thread_para paras[THREAD_NUM_MAX];
double sum = 0, speed = 0;
double *instant_speed = NULL;
int speed_num = 0;
gettimeofday(&s_time, NULL);
init_instant_speed(&instant_speed, &speed_num);
for ( i = 0; i < num_thread; i++) {
memset(¶s[i], 0, sizeof(struct thread_para));
sprintf(paras[i].url, "%s/speedtest/upload.%s", p_url, p_ext);
paras[i].result = 0;
paras[i].finish = 0;
paras[i].upload_size = size/num_thread;
//printf("szeleft = %ld\n", paras[i].upload_size);
error = pthread_create(¶s[i].tid, NULL, (void*)do_upload, (void*)¶s[i]);
if ( error != 0)
printf("Can't Run thread num %d, error %d\n", i, error);
}
if (init != 0)
{
loop_threads(paras, num_thread, instant_speed, &speed_num);
}
for (i = 0;i < num_thread; i++) {
pthread_join(paras[i].tid, NULL);
sum += paras[i].result;
}
if (init != 0) {
speed = calculate_average_speed(instant_speed, speed_num);
}else {
struct timeval e_time;
int time;
gettimeofday(&e_time, NULL);
time = calc_past_time(&s_time, &e_time);
speed = (sum*1000)/time; //bytes per second
}
//printf("msec = %d speed = %0.2fMbps\n", time, ((sum*8*1000/time))/(1024*1024));
free(instant_speed);
return speed;
}
static int get_download_filename(double speed, int num_thread)
{
int i;
int filelist[] = {350, 500, 750, 1000, 1500, 2000, 3000, 3500, 4000};
int num_file = ARRAY_SIZE(filelist);
for (i = 1; i < num_file; i++) {
int time;
float times = (float)filelist[i]/350;
//printf("time %f speed %lf\n", times, speed);
times = (times*times);
time = (num_thread*times*FILE_350_SIZE)/speed;
//printf("%d %d %f\n", filelist[i], time, times);
if (time > SPEEDTEST_TIME_MAX)
break;
}
if (i < num_file)
return filelist[i - 1];
return filelist[num_file - 1];
}
static int get_upload_extension(char *server, char *p_ext)
{
CURL *curl;
CURLcode res;
struct web_buffer web;
char* p = NULL;
int i;
memset(&web, 0, sizeof(web));
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, server);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_web_buf);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &web);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
return NOK;
}
p = strstr(web.data, UPLOAD_EXTENSION_TAG);
if (p == NULL ||
sscanf(p + strlen(UPLOAD_EXTENSION_TAG), "%*[^a-zA-Z]%[a-zA-Z]", p_ext) <= 0) {
fprintf(stderr, "Upload extension not found\n");
return NOK;
}
printf("Upload extension: %s\n", p_ext);
return OK;
}
static int get_client_info(struct client_info *p_client)
{
CURL *curl;
CURLcode res;
XML_Parser xml = XML_ParserCreate(NULL);
struct web_buffer web;
char* p = NULL;
int i;
memset(&web, 0, sizeof(web));
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "https://www.speedtest.net/speedtest-config.php");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_web_buf);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &web);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "haibbo speedtest-cli");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
return NOK;
}
XML_SetUserData(xml, p_client);
XML_SetElementHandler(xml, start_element, end_element);
if (XML_Parse(xml, web.data, web.size , 1) == XML_STATUS_ERROR) {
fprintf(stderr, "Parse client failed\n");
exit(-1);
}
free(web.data);
return OK;
}
static int get_closest_server()
{
CURL *curl;
CURLcode res;
XML_Parser xml = XML_ParserCreate(NULL);
struct web_buffer web;
char* p = NULL;
int i;
struct server_info server;
memset(&web, 0, sizeof(web));
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "http://www.speedtest.net/speedtest-servers.php");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_web_buf);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &web);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; rv:22.0) Gecko/20130405 Firefox/22.0");
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
return NOK;
}
XML_SetUserData(xml, &server);
depth = 0;
XML_SetElementHandler(xml, start_element, end_element);
if (XML_Parse(xml, web.data, web.size , 1) == XML_STATUS_ERROR) {
fprintf(stderr, "Parse servers list failed\n");
exit(-1);
}
return OK;
}
static int get_best_server(int *p_index)
{
int i;
double minimum = DBL_MAX;
char server[URL_LENGTH_MAX] = {0};
for (i = 0; i < MAX_CLOSEST_SERVER_NUM; i++) {
double latency;
sscanf(servers[i].url, "http://%[^/]speedtest/upload.%*s", server);
latency = test_latency(server);
if (minimum > latency ) {
minimum = latency;
*p_index = i;
}
}
if (minimum == DBL_MAX)
return NOK;
return OK;
}
int main(int argc, char *argv[])
{
int opt, num_thread;
char server_url[URL_LENGTH_MAX], ext[UPLOAD_EXT_LENGTH_MAX];
double latency, speed, download_speed, upload_speed;
int dsize, sindex;
sindex = -1;
num_thread = 4;
dsize = INIT_DOWNLOAD_FILE_RESOLUTION;
memset(server_url, 0, sizeof(server_url));
memset(ext, 0, sizeof(ext));
while ( (opt = getopt(argc, argv, "p:s:lh")) > 0) {
switch (opt) {
case 'p':
if (atoi(optarg) > THREAD_NUM_MAX) {
fprintf(stderr, "Only support %d threads meanwhile", THREAD_NUM_MAX);
exit(-1);
}
num_thread = atoi(optarg);
break;
case 's':
strncpy(server_url, optarg, URL_LENGTH_MAX);
break;
case 'l':
break;
case 'h':
show_usage(argv);
break;
}
}
if (server_url[0] == 0) {
printf("Retrieving speedtest.net configuration...\n");
get_client_info(&client);
printf("Retrieving speedtest.net server list...\n");
get_closest_server();
printf("Testing from %s (%s)...\n", client.isp, client.ip);
printf("Selecting best server based on ping...\n");
get_best_server(&sindex);
sscanf(servers[sindex].url, "http://%[^/]/speedtest/upload.%4s", server_url, ext);
printf("Bestest server: %s(%0.2fKM)\n", server_url, servers[sindex].distance);
}
//strcpy(server_url,"www.gdspeedtest.com:8080");
/* Must initialize libcurl before any threads are started */
curl_global_init(CURL_GLOBAL_ALL);
latency = test_latency(server_url);
if (latency == DBL_MAX)
exit(-1);
printf("Server latency is %0.0fms\n", latency);
speed = test_download(server_url, num_thread, dsize, 0);
dsize = get_download_filename(speed, num_thread);
fprintf(stderr, "Testing download speed");
download_speed = test_download(server_url, num_thread, dsize, 1);
printf("Download speed: %0.2fMbps\n", ((download_speed*8)/(1024*1024)));
if (ext[0] == 0 && get_upload_extension(server_url, ext) != OK)
exit(-1);
speed = test_upload(server_url, num_thread, speed, ext, 0);
fprintf(stderr, "Testing upload speed");
upload_speed = test_upload(server_url, num_thread, speed*SPEEDTEST_TIME_MAX, ext, 1);
printf("Upload speed: %0.2fMbps\n", ((upload_speed*8)/(1024*1024)));
}
//参照https://github.com/haibbo/speedtest-cli
复制代码
编写makefile
speedtest_cli: main.c
gcc $< -lpthread -lcurl -lexpat -lm -o $@ I./lib/include -L./lib -L./lib -Wl,-rpath,/home/root/lib/
clean:
rm speedtest_cli
将编好的库、头文件移到makefile对应的位置,编译出speedtest_cli,放入开发板验证
03-13