ادامه مرحله سی دوم : معرفی و کار با شبکه / استفاده از پروتکل های HTTP و FTP
خب حالا بیاییم سراغ تجزیه تحلیل این کلاس ببینیم توش چه خبره...
ابتدا موارد زیر رو اینکلود کردیم :
#include "myhttp.h"
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>
دلیلشون واظحه ! اولیرو حتما باید اینکلود کنیم چون بدون اون دسترسی به کلاس و توابع از پیش تعریف شده در فایل .h امکانپذیر نخواهد بود.
QFileInfo برای کار با اطلاعات فایل هستش و گزینه QDateTime هم خب برای کار با تاریخو زمانو اینجور چیزا و در نهایت QDebug برای کار QDebug که من خودم شخصا ازش متنفرم چون خیلی ضعیفتر از std::cout عمل میکنه ولی خب طی این آموزش ها از همین روش استفاده میکنیم هرچند هیچ موردی نخواهد داشت اگه شما در پروژه هاتون به جای QDebug از iostream و فراخوانی std::cout برای چاپ موارد مورد نظرتون استفاده کنید فقط در بعضی از موارد باید عمل تبدیل QString به StdString ها رو رعایت کنید و در رابطه با مقادیر دیگه هم همینطوره...
خب در خط بعدی به صورت زیر...
MyHttp::MyHttp(QObject *parent) :
QObject(parent)
, _pManager(NULL)
, _pCurrentReply(NULL)
, _pFile(NULL)
, _nDownloadTotal(0)
, _bAcceptRanges(false)
, _nDownloadSize(0)
, _nDownloadSizeAtPause(0)
{
}
اینجا ما کلاسمون رو فراخوانی کردیم همراه با آبجکت هاش و هر یک از کلاس های مشتق شده آن که به نوعی کپی از کلاس ها برای استفاده از آن گرفته شده اند در اینجا آمده است که ابتدا برای هر یک مقادیر پیشفرض بر اساس نوع آنها مشخص شده است.
در خط بعدی به صورت زیر ...
MyHttp::~MyHttp()
{
if (_pCurrentReply != NULL)
{
pause();
}
}
در بدنه کلاس ویرانگر دستور شرطی آمده که اگر پاسخی ارسال شده از طرف سرور به صورت NULL نباشد تابع pause اجرا خواهد گردید.
حالا در مرحله بعدی به صورت زیر....
void MyHttp::download(QUrl url)
{
qDebug() << "download: URL=" << url.toString();
_URL = url;
{
QFileInfo fileInfo(url.toString());
_qsFileName = fileInfo.fileName();
}
_nDownloadSize = 0;
_nDownloadSizeAtPause = 0;
_pManager = new QNetworkAccessManager(this);
_CurrentRequest = QNetworkRequest(url);
_pCurrentReply = _pManager->head(_CurrentRequest);
_Timer.setInterval(5000);
_Timer.setSingleShot(true);
connect(&_Timer, SIGNAL(timeout()), this, SLOT(timeout()));
_Timer.start();
connect(_pCurrentReply, SIGNAL(finished()), this, SLOT(finishedHead()));
connect(_pCurrentReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
}
تابع download رو فراخوانی کردیم که حاوی پارامتر Url از نوع QUrl هستش که در حین اجرا ابتدا آدرسی که مختص فایل قابل دانلود هستش رو میگیره و به صورت زیر...
qDebug() << "download: URL=" << url.toString();
یک کد چاپ برای آدرسی که ارسال کردیم برای دانلود.
_URL = url;
{
QFileInfo fileInfo(url.toString());
_qsFileName = fileInfo.fileName();
}
اینجا آدرس ارسال شده توسط کاربر دریافت و مشخصات آدرس توسط کلاس QFileInfo بررسی و نام فایل از آدرس گرفته شده و به متغیر از قبل تعریف شده یعنی _qsFileName ارسال میشود.
در خط بعدی کد های زیر...
_nDownloadSize = 0;
_nDownloadSizeAtPause = 0;
مقدار 0 رو به متغیر های _nDownloadSize و همچنین _nDownloadSizeAtPause اختصاص میدیم.
حالا اینجا کلاس اصلی ما که ازش استفاده خواهیم کرد وار کار خواهد شد به صورت زیر...
_pManager = new QNetworkAccessManager(this);
_CurrentRequest = QNetworkRequest(url);
اینجا مقدار کلاس مشتق شده _pManager رو برابر کلاس اصلی QNetworkAccessManager مشخص میکنیم و همچنین کلاس های _CurrentRequest رو با درخواست کننده آدرس یعنی QNetworkRequest با پارامتر url اختصاص میدیم.
در این خط به صورت زیر ...
_pCurrentReply = _pManager->head(_CurrentRequest);
مقدار _pCurrentReply رو برابر میکنیم با هیدر (Header) ای که توسط کلاس _CurrentRequest گرفته شده.
خط های زیر...
_Timer.setInterval(5000);
_Timer.setSingleShot(true);
خب ایجا ما نیاز داریم به مدت زمانی که باید توسط تایمرمون ایجاد کنیم برای مثال در اینجا میانگین زمانی رو برابر 5000 میلی ثانیه قرار دادیم و در خط بعدیش مقدار SingleShot یا همان تایمر شات که یکی از پراپرتی های QTimer هستش رو برابر با true قرار دادیم.
و در خط های زیر...
connect(&_Timer, SIGNAL(timeout()), this, SLOT(timeout()));
_Timer.start();
توسط تابع connect سیگنال ارسالی توسط تایمر رو توسط تابع timeout ارسال و مجددا سیگنال بازگشتی یا همان اسلات رو توسط تابع timeout ارسال میکنیم.
connect(_pCurrentReply, SIGNAL(finished()), this, SLOT(finishedHead()));
connect(_pCurrentReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(error(QNetworkReply::NetworkError)));
این دو کد نهایی عمل اتصال بین سیگنال و اسلات برای ارسال و دریافت جواب به عنوان اتمام کار انجام خواهند داد و در خط بعدی همین کار رو برای زمانی که ارتباط با مشکل برخورده باشه ایجاد میکنیم.