Весь нижеприведенный код — выдержка из одного моего недавнего проекта, в рамках которого было необходимо определять скорость download и upload. Изобретать велосипед было неохота, посему возникло желание воспользоваться сервисом www.speedtest.net, как наиболее уважаемым и работоспособным из сервисов такого типа. Впрочем, как показала практика, он оказался вполне недружелюбным и некий велосипед таки пришлось изобрести.
Итак, начал я данную часть работы с перекапывания Гугла и нашел таки одну интересную ссылочку — http://speedtest.net/speedtest-config.php, по которой грузится немаленькая XML-ка, начало которой я приведу ниже.
И вся дальнейшая xml — это список серверов, на которых установлена серверная компонента speedtest-а. Когда я понял, что параметры lat и lon — это не что иное, как latitude и longitude, сиречь широта и долгота, и искать ближайший ко мне сервер придется руками — меня бросило в холодный пот. «Шлимазлы», — подумал я и тут началась магия большого C++.
Функция _sendPacket являет собой простое конструирование http-пакета, никакого научного интереса в себе не несет, посему, с вашего позволения, я ее пропущу. Перейдем сразу к _getConfig.
Как видно из кода — идет получение, последующий разбор XML и заполнение вектора структур _ServerLocation. В целях непротивления велосипедам насилием поиск ближайшего сервера был оформлен под вызов STL-евского sort, для чего пришлось написать функтор сортировки.
Школьный курс не то географии, не то геометрии в действии, ну, а ближайший сервер найден.
Дальше становится не так интересно, потому что сам код измерения скорости — тривиален.
Может быть, кому-нить и пригодится. Протестирован код был на Visual Studio 2010 (остальная часть проекта была заточена под Windows).
Хочу сказать спасибо документации по STL и Boost, а также кускам исходников, найденых мною на просторах Интернета для самообучения.
Полный код данного опуса доступен по ссылке http://paste.pocoo.org/show/215424/
______________________
Итак, начал я данную часть работы с перекапывания Гугла и нашел таки одну интересную ссылочку — http://speedtest.net/speedtest-config.php, по которой грузится немаленькая XML-ка, начало которой я приведу ниже.
-
- <?xml version="1.0" encoding="UTF-8"?>
- <settings>
- <client ip="*.*.*.*" lat="60.0000" lon="100.0000" isp="Samara Telecom, JSC" isprating="3.3" rating="5" ispdlavg="4449" ispulavg="1394" />
- <licensekey>9c1687ea58e5e770-1df5b7cd427370f7-4b62a84526ea1f56</licensekey>
- <customer>speedtest</customer>
- <servers><server url="http://speedtest.pronea.no/speedtest/upload.php" lat="69.6828" lon="18.9428" name="Tromso" country="Norway" countrycode="NO" sponsor="Pronea AS" sponsorurl="http://www.pronea.no/" id="1327" gid="0" bigsamples="1" />
- <server url="http://test.nax.no/speedtest/upload.php" lat="65.8333" lon="13.2000" name="Helgeland" country="Norway" countrycode="NO" sponsor="Noraxess Broadband" sponsorurl="http://www.nax.no" id="1362" gid="0" url2="http://85.221.66.41/speedtest/upload.php" bigsamples="1" />
-
И вся дальнейшая xml — это список серверов, на которых установлена серверная компонента speedtest-а. Когда я понял, что параметры lat и lon — это не что иное, как latitude и longitude, сиречь широта и долгота, и искать ближайший ко мне сервер придется руками — меня бросило в холодный пот. «Шлимазлы», — подумал я и тут началась магия большого C++.
Функция _sendPacket являет собой простое конструирование http-пакета, никакого научного интереса в себе не несет, посему, с вашего позволения, я ее пропущу. Перейдем сразу к _getConfig.
-
- void _getConfig()
- {
- std::stringstream netspeedConfigStream = _sendPacket(_SpeedtestServer, _SpeedtestConfigUrl);
-
- // Create empty property tree object
- using boost::property_tree::ptree;
- ptree PropertyTree;
-
- // Load XML file and put its contents in property tree.
- // No namespace qualification is needed, because of Koenig
- // lookup on the second argument. If reading fails, exception
- // is thrown.
- read_xml(netspeedConfigStream, PropertyTree);
-
- ptree Settings = PropertyTree.get_child("settings");
-
- // Construct client location
- _ServerLocation *_ClientLocation;
-
- // Declare list of Server Locations
- std::vector<_ServerLocation> *_ServerLocationList;
-
- _ClientLocation = new _ServerLocation(Settings.begin()->second, false);
- _ServerLocationList = new std::vector<_ServerLocation>;
-
- // Construct list from XML
- BOOST_FOREACH(ptree::value_type &v, PropertyTree.get_child("settings.servers"))
- _ServerLocationList->push_back(_ServerLocation(v.second, true));
-
- std::sort(_ServerLocationList->begin(), _ServerLocationList->end(), _ServerLocationSortFunctor(_ClientLocation) );
-
- // Url of the nearest server
- std::vector<std::string> SplitUrl;
-
- boost::split(SplitUrl, _ServerLocationList->begin()->GetUrl(), boost::is_any_of("/"));
-
- delete _ClientLocation;
- delete _ServerLocationList;
-
- _NearestServer = SplitUrl[2];
-
- for (int i = 3; i < SplitUrl.size()-1; ++i) // TODO: rewrite with iterators
- {
- _NearestServerUrl.append("/");
- _NearestServerUrl.append(SplitUrl[i]);
- }
-
- return;
- }
-
Как видно из кода — идет получение, последующий разбор XML и заполнение вектора структур _ServerLocation. В целях непротивления велосипедам насилием поиск ближайшего сервера был оформлен под вызов STL-евского sort, для чего пришлось написать функтор сортировки.
-
- struct _ServerLocationSortFunctor
- {
- public:
- _ServerLocationSortFunctor(_ServerLocation* ClientLocation) : _ClientLocation(ClientLocation) {}
-
- bool operator() (_ServerLocation& _First, _ServerLocation& _Second)
- {
- return _ServerDist(_ClientLocation, &_First) < _ServerDist(_ClientLocation, &_Second);
- }
-
- private:
- _ServerLocation* _ClientLocation;
-
- inline double deg2rad(double ServerAplpha)
- {
- return ServerAplpha*PI/180;
- }
-
- inline double hypot3(double dx, double dy, double dz)
- {
- return sqrt(dx*dx + dy*dy+dz*dz);
- }
-
- double _ServerDist(_ServerLocation* _First, _ServerLocation* _Second)
- {
- double phi1 = deg2rad(_First->GetLon());
- double psi1 = deg2rad(_First->GetLat());
- double phi2 = deg2rad(_Second->GetLon());
- double psi2 = deg2rad(_Second->GetLat());
-
- double cos_psi1 = cos(psi1);
- double x1 = EarthRadius*cos(phi1)*cos_psi1;
- double y1 = EarthRadius*sin(phi1)*cos_psi1;
- double z1 = EarthRadius*sin(psi1);
-
- double cos_psi2 = cos(psi2);
- double x2 = EarthRadius*cos(phi2)*cos_psi2;
- double y2 = EarthRadius*sin(phi2)*cos_psi2;
- double z2 = EarthRadius*sin(psi2);
-
- double d = hypot3(x2-x1, y2-y1, z2-z1);
-
- return EarthRadius*acos(1-(d*d)/(2*EarthRadius*EarthRadius));
- }
-
- };
-
Школьный курс не то географии, не то геометрии в действии, ну, а ближайший сервер найден.
Дальше становится не так интересно, потому что сам код измерения скорости — тривиален.
-
- void _testLatency()
- {
- std::string Url(_NearestServerUrl);
- Url.append(_LatencyUrl);
-
- boost::timer LatencyTimer;
- _sendPacket(_NearestServer, Url);
- _LatencyTime = LatencyTimer.elapsed();
-
- std::cout << "PING: " << _LatencyTime << std::endl;
-
- return;
- }
-
- void _testDownload()
- {
- std::string Url(_NearestServerUrl);
- Url.append(_DownloadUrl);
-
- boost::timer DownloadTimer;
- std::stringstream DownloadPacket = _sendPacket(_NearestServer, Url);
- double DownloadTime = DownloadTimer.elapsed();
-
- double DownloadSpeed = (DownloadPacket.str().length() / (DownloadTime - _LatencyTime)) * 8 / 1024;
-
- std::cout << "DOWNLOAD: " << DownloadSpeed << std::endl;
-
- return;
- }
-
- void _testUpload()
- {
- std::string Url(_NearestServerUrl);
- Url.append(_UploadUrl);
-
- std::string UploadDataValue(_UploadBytes, 'a');
- std::string UploadData("content0=");
-
- UploadData += UploadDataValue;
-
- boost::timer UploadTimer;
- _sendPacket(_NearestServer, Url, true, UploadData);
- double UploadTime = UploadTimer.elapsed();
-
- double UploadSpeed = (_UploadBytes / (UploadTime - _LatencyTime)) * 8 / 1024;
-
- std::cout << "UPLOAD: " << UploadSpeed << std::endl;
-
- }
-
Может быть, кому-нить и пригодится. Протестирован код был на Visual Studio 2010 (остальная часть проекта была заточена под Windows).
Хочу сказать спасибо документации по STL и Boost, а также кускам исходников, найденых мною на просторах Интернета для самообучения.
Полный код данного опуса доступен по ссылке http://paste.pocoo.org/show/215424/
______________________