接上面,进一步分析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()、最后处理通知消息。

转载于:https://www.cnblogs.com/MingZznet/articles/3210751.html

QT分析之网络编程(七)相关推荐

  1. 不为人知的网络编程(七):如何让不可靠的UDP变的可靠?

    为什么80%的码农都做不了架构师?>>>    本文内容来自学霸君资深架构师袁荣喜的技术分享. 1.前言 最近和很多实时音视频领域的朋友交流中都有谈论到 RUDP(Reliable ...

  2. Linux网络编程-七

    Linux网络编程-七 web服务器项目 1 web服务器开发准备 1.1 Html语言基础(和Markdown一个性质,某些程度上和Markdown通用,所以我在编辑的时候在<>里都加了 ...

  3. Qt:Qt实现Winsock网络编程—TCP服务端和客户端通信(多线程)

    Qt实现Winsock网络编程-TCP服务端和客户端通信(多线程) 前言 感觉Winsock网络编程的api其实和Linux下网络编程的api非常像,其实和其他编程语言的网络编程都差不太多.博主用Qt ...

  4. Qt:Qt实现Winsock网络编程—非阻塞模式下的简单远程控制的开发(WSAAsyncSelect)

    Qt实现Winsock网络编程-非阻塞模式下的简单远程控制的开发(WSAAsyncSelect) 前言 这边博客应该是 Qt实现Winsock网络编程-TCP服务端和客户端通信(多线程) 的姐妹篇,上 ...

  5. Qt中的网络编程(TCP)

    在Qt中网络编程主要由Qt Network模块来编写基于TCP/Ip的网络程序,其中提供了许多的类: 可以点击该链接查看:Qt网络C++类|Qt网络 5.15.12  常见的有: QTcpServer ...

  6. 5.关于QT中的网络编程,QTcpSocket,QUdpSocket

     1 新建一个项目:TCPServer.pro A  修改TCPServer.pro,注意:如果是想使用网络库,需要加上network SOURCES += \ TcpServer.cpp \ T ...

  7. QT入门第七天 网络编程TCP/IP/UDP+Http和JSON解析+qt事件软键盘【CSDN最详细】

    网络编程+Http和JSON解析+qt事件软键盘 第一章 QT中的网络编程 [1]涉及到的类 [2]tcp协议的流程 [2.1]服务器的流程 socket-->bind-->listen- ...

  8. 查看队列深度_不为人知的网络编程(十一):从底层入手,深度分析TCP连接耗时的秘密...

    " 本文作者张彦飞,原题"聊聊TCP连接耗时的那些事儿",本次收录已征得作者同意,转载请联系作者.即时通讯网收录时有少许改动.本文已同步发布于52im社区:http:// ...

  9. [Qt教程] 第31篇 网络(一)Qt网络编程简介

    [Qt教程] 第31篇 网络(一)Qt网络编程简介 楼主  发表于 2013-8-28 17:04:17 | 查看: 515| 回复: 0 Qt网络编程简介 版权声明 该文章原创于作者yafeilin ...

  10. 【Qt入门第31篇】 网络(一)Qt网络编程简介

    导语 从这一节开始我们讲述Qt网络应用方面的编程知识.在开始这部分知识的学习之前,大家最好已经拥有了一定的网络知识和Qt的编程基础.在后面的教程中我们不会对一个常用的网络名词进行详细的解释,对于不太了 ...

最新文章

  1. 7.Array 数组对象
  2. [Spring cloud 一步步实现广告系统] 22. 广告系统回顾总结
  3. python中df去重_Python中DataFrame去重
  4. VelocityTracker简要
  5. 【CodeForces - 1A】Theatre Square(水题,几何)(CODEFORCES,梦的开始)
  6. WORD设置别人只可阅读,不可更改文档?
  7. linux同一目录文件无法执行,linux – 无法在特定目录中执行文件
  8. mysql 42
  9. oracle数据库管理和日常维护,oracle数据库管理与维护
  10. http和https协议下,http可以正常下载,但是https却不能
  11. 积分商城功能表设计结构以及积分功能模块
  12. 代理服务器使用全攻略(转)
  13. nltk中文分句_如何改进NLTK的分句技术?
  14. traceroute出现*的分析
  15. 能上QQ不能打开网页的解决方法
  16. c语言入门之项目3.6——利用for循环输出一个直角三角形
  17. 张江创业者说 | 影创科技孙立:改变世界,从改变视野开始
  18. aucc2018插件_你的Au cc2018 新功能你都了解多少?
  19. 机器学习技法11: Gradient Boosted Decision Tree(GBDT)
  20. 2021年电工(初级)考试题及电工(初级)考试题库

热门文章

  1. 我中招了:解喝汽水问题
  2. 小马儿随笔十一:朋友一生一起走
  3. MindManager思维导图中文版免费下载使用教程
  4. 用了几年的 Fastjson,我最终替换成了Jackson!
  5. 架构篇:高可用 Redis 服务架构分析与搭建
  6. 运维定位服务故障时,前5分钟都在忙啥?
  7. 程序员如何转型项目经理?
  8. js 运行中断停止_如何终止JS继续运行??
  9. 百度地图手机端单触点单击和长按事件,解决部分手机(小米手机)地图单击事件失效,多触点、拖动依然触发长按的bug...
  10. 【BZOJ】3576: [Hnoi2014]江南乐