QT分析之网络编程(七)

简介: 接上面,进一步分析QNetworkAccessManager::createRequest()的实现。去除不重要的分支末节,看其调用的QNetworkReplyImplPrivate::setup()和QNetworkAccessManagerPrivate::findBackend()的代码。
接上面,进一步分析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()
{
    if (!factoryDataShutdown) {
        QMutexLocker locker(&factoryData()->mutex);
        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;

    return 0;
}
如果是能够处理的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()、最后处理通知消息。
目录
相关文章
|
1月前
|
安全 编译器 C++
【Qt 面试题】Qt信号槽机制与优势与不足
【Qt 面试题】Qt信号槽机制与优势与不足
29 1
|
1月前
|
网络协议 安全 网络安全
Qt 套接字类(QTcpSocket和QUdpSocket)解密:迈向 Qt 网络编程之巅
Qt 套接字类(QTcpSocket和QUdpSocket)解密:迈向 Qt 网络编程之巅
91 0
|
8月前
|
数据可视化 算法 数据库
GUI、多线程编程、网络编程简介
GUI 是 Graphical User Interface 的缩写,含义为图形用户界面。它是一种计算机操作界面,通过图形、图标和视觉化元素与用户进行交互。相比于命令行界面(CLI),GUI 提供了更直观、更易用的方式让用户与计算机系统进行交互。
91 0
|
4月前
|
API
[QT5] QT5基本知识
[QT5] QT5基本知识
36 0
|
10月前
|
存储 编译器 C语言
C++学习:从基础到QT实现
C++学习:从基础到QT实现
206 0
项目实战:Qt编译Qt库以及使用C#调用Qt库,并实现C#集成Qt的tcp客户端
项目实战:Qt编译Qt库以及使用C#调用Qt库,并实现C#集成Qt的tcp客户端
项目实战:Qt编译Qt库以及使用C#调用Qt库,并实现C#集成Qt的tcp客户端
|
数据安全/隐私保护
|
存储 网络协议 网络安全
Qt之网络编程
简述 Qt Network模块提供的类允许编写 TCP/IP clients 和 servers。 其中包含一些低级别的类,例如:QTcpSocket、QTcpServer 和 QUdpSocket,表示低级的网络概念;一些高级别的类,例如:QNetworkRequest、QNetworkReply 和 QNetworkAccessManager,使用常见的协议执行网络操
2485 0
|
网络协议
5.关于QT中的网络编程,QTcpSocket,QUdpSocket
 1 新建一个项目:TCPServer.pro A  修改TCPServer.pro,注意:如果是想使用网络库,需要加上network SOURCES += \     TcpServer.cpp \     TcpClient.cpp   HEADERS += \     TcpServer.h
2193 0

推荐镜像

更多