接上面,進一步分析QNetworkAccessManager::createRequest()的實作。去除不重要的分支末節,看其調用的QNetworkReplyImplPrivate::setup()和QNetworkAccessManagerPrivate::findBackend()的代碼。
void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,
QIODevice *data)
{
Q_Q(QNetworkReplyImpl);
outgoingData = data;
request = req;
url = request.url();
operation = op;
if (outgoingData) { // outgoingData實際就是QNetworkRequest對象
q->connect(outgoingData, SIGNAL(readyRead()), SLOT(_q_sourceReadyRead()));
q->connect(outgoingData, SIGNAL(readChannelFinished()), SLOT(_q_sourceReadChannelFinished()));
}
q->QIODevice::open(QIODevice::ReadOnly); // ???
QMetaObject::invokeMethod(q, "_q_startOperation", Qt::QueuedConnection);
}
連接配接兩個信号與槽之後,是打開QIODevice,暫未深入分析。然後是呼叫q->_q_startOperation(),實際就是調用QNetworkReplyImpl::_q_startOperation(),使用的是隊列等待方式(也就是發送一個消息進入系統消息隊列,這個setup函數以及全部後續執行完畢,主動權交回給Windows後,再根據進入隊列的消息來觸發)。
是以我們先看QNetworkAccessManagerPrivate::findBackend()的代碼實作:
QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessManager::Operation op,
const QNetworkRequest &request)
QNetworkRequest::CacheLoadControl mode =
static_cast<QNetworkRequest::CacheLoadControl>(
request.attribute(QNetworkRequest::CacheLoadControlAttribute,
QNetworkRequest::PreferNetwork).toInt());
if (mode == QNetworkRequest::AlwaysCache
&& (op == QNetworkAccessManager::GetOperation
|| op == QNetworkAccessManager::HeadOperation)) {
QNetworkAccessBackend *backend = new QNetworkAccessCacheBackend;
backend->manager = this;
return backend;
if (!factoryDataShutdown) {
QMutexLocker locker(&factoryData()->mutex);
QNetworkAccessBackendFactoryData::ConstIterator it = factoryData()->constBegin(),
end = factoryData()->constEnd();
while (it != end) {
QNetworkAccessBackend *backend = (*it)->create(op, request);
if (backend) {
backend->manager = this;
return backend; // found a factory that handled our request
}
++it;
}
return 0;
這段代碼有一點複雜,先看紅色标記的第一句,factoryData()是用宏來定義的函數:
Q_GLOBAL_STATIC(QNetworkAccessBackendFactoryData, factoryData)
宏定義如下:
#define Q_GLOBAL_STATIC(TYPE, NAME) \
static TYPE *NAME() \
{ \
static TYPE this_##NAME; \
static QGlobalStatic<TYPE > global_##NAME(&this_##NAME); \
return global_##NAME.pointer; \
如果對STD比較熟悉,第一感覺這是一個模闆List操作。在這裡constBegin()和constEnd()組合起來是一個周遊,那麼在什麼地方設定值呢?良好代碼的命名是很規範的,我試了試全局查找factoryData(),找到了我所希望看到的東西:
QNetworkAccessBackendFactory::QNetworkAccessBackendFactory()
QMutexLocker locker(&factoryData()->mutex);
factoryData()->prepend(this);
QNetworkAccessBackendFactory::~QNetworkAccessBackendFactory()
factoryData()->removeAll(this);
這裡prepend()應該是把對象添加到清單;而removeAll()就是清空全部資料了。
factoryData()裡面包含的對象序列,應該是從QNetworkAccessBackendFactory衍生出來的。
一共有哪些子類呢?繼續全局查找:
class QNetworkAccessDataBackendFactory: public QNetworkAccessBackendFactory
class QNetworkAccessDebugPipeBackendFactory: public QNetworkAccessBackendFactory
class QNetworkAccessFileBackendFactory: public QNetworkAccessBackendFactory
class QNetworkAccessFtpBackendFactory: public QNetworkAccessBackendFactory
class QNetworkAccessHttpBackendFactory : public QNetworkAccessBackendFactory
去除暫時不關心的DebugPipe,一共有四種:DataBackend、FileBackend、FtpBackend、HttpBackend。媒體的種類原來是在這裡實作的。看其中QNetworkAccessHttpBackendFactory::create()
QNetworkAccessBackend *
QNetworkAccessHttpBackendFactory::create(QNetworkAccessManager::Operation op,
const QNetworkRequest &request) const
// check the operation
switch (op) {
case QNetworkAccessManager::GetOperation:
case QNetworkAccessManager::PostOperation:
case QNetworkAccessManager::HeadOperation:
case QNetworkAccessManager::PutOperation:
break;
default:
// no, we can't handle this request
return 0;
QUrl url = request.url();
QString scheme = url.scheme().toLower();
if (scheme == QLatin1String("http") || scheme == QLatin1String("https"))
return new QNetworkAccessHttpBackend;
如果是能夠處理的OP标記并且URL的字首是http或者是https,則建立一個QNetworkAccessHttpBackend對象。
前面QNetworkAccessManager::get()代碼中,調用的參數是QNetworkAccessManager::GetOperation,是以在我們分析的這個應用中,建立的是QNetworkAccessHttpBackend對象。
findBackend()到此分析完畢;由于factoryData()的具體實作跟我們分析網絡通信的目标沒有太大關系,未深入分析,有誰分析了的話請轉告一聲,值得一看。
回到前面暫停的QNetworkReplyImpl::_q_startOperation(),又實作了什麼動作呢?
void QNetworkReplyImplPrivate::_q_startOperation()
// This function is called exactly once
state = Working;
if (!backend) {
error(QNetworkReplyImpl::ProtocolUnknownError,
QCoreApplication::translate("QNetworkReply", "Protocol \"%1\" is unknown").arg(url.scheme())); // not really true!;
finished();
return;
backend->open();
if (state != Finished) {
if (operation == QNetworkAccessManager::GetOperation)
pendingNotifications.append(NotifyDownstreamReadyWrite);
if (outgoingData) {
_q_sourceReadyRead();
handleNotifications();
首先調用了剛剛建立的QNetworkAccessHttpBackend::open(),然後是添加通知消息、調用_q_sourceReadyRead()、最後處理通知消息。