QT分析之网络编程(七)
接上面,进一步分析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分析之网络编程(七)相关推荐
- 不为人知的网络编程(七):如何让不可靠的UDP变的可靠?
为什么80%的码农都做不了架构师?>>> 本文内容来自学霸君资深架构师袁荣喜的技术分享. 1.前言 最近和很多实时音视频领域的朋友交流中都有谈论到 RUDP(Reliable ...
- Linux网络编程-七
Linux网络编程-七 web服务器项目 1 web服务器开发准备 1.1 Html语言基础(和Markdown一个性质,某些程度上和Markdown通用,所以我在编辑的时候在<>里都加了 ...
- Qt:Qt实现Winsock网络编程—TCP服务端和客户端通信(多线程)
Qt实现Winsock网络编程-TCP服务端和客户端通信(多线程) 前言 感觉Winsock网络编程的api其实和Linux下网络编程的api非常像,其实和其他编程语言的网络编程都差不太多.博主用Qt ...
- Qt:Qt实现Winsock网络编程—非阻塞模式下的简单远程控制的开发(WSAAsyncSelect)
Qt实现Winsock网络编程-非阻塞模式下的简单远程控制的开发(WSAAsyncSelect) 前言 这边博客应该是 Qt实现Winsock网络编程-TCP服务端和客户端通信(多线程) 的姐妹篇,上 ...
- Qt中的网络编程(TCP)
在Qt中网络编程主要由Qt Network模块来编写基于TCP/Ip的网络程序,其中提供了许多的类: 可以点击该链接查看:Qt网络C++类|Qt网络 5.15.12 常见的有: QTcpServer ...
- 5.关于QT中的网络编程,QTcpSocket,QUdpSocket
1 新建一个项目:TCPServer.pro A 修改TCPServer.pro,注意:如果是想使用网络库,需要加上network SOURCES += \ TcpServer.cpp \ T ...
- QT入门第七天 网络编程TCP/IP/UDP+Http和JSON解析+qt事件软键盘【CSDN最详细】
网络编程+Http和JSON解析+qt事件软键盘 第一章 QT中的网络编程 [1]涉及到的类 [2]tcp协议的流程 [2.1]服务器的流程 socket-->bind-->listen- ...
- 查看队列深度_不为人知的网络编程(十一):从底层入手,深度分析TCP连接耗时的秘密...
" 本文作者张彦飞,原题"聊聊TCP连接耗时的那些事儿",本次收录已征得作者同意,转载请联系作者.即时通讯网收录时有少许改动.本文已同步发布于52im社区:http:// ...
- [Qt教程] 第31篇 网络(一)Qt网络编程简介
[Qt教程] 第31篇 网络(一)Qt网络编程简介 楼主 发表于 2013-8-28 17:04:17 | 查看: 515| 回复: 0 Qt网络编程简介 版权声明 该文章原创于作者yafeilin ...
- 【Qt入门第31篇】 网络(一)Qt网络编程简介
导语 从这一节开始我们讲述Qt网络应用方面的编程知识.在开始这部分知识的学习之前,大家最好已经拥有了一定的网络知识和Qt的编程基础.在后面的教程中我们不会对一个常用的网络名词进行详细的解释,对于不太了 ...
最新文章
- 7.Array 数组对象
- [Spring cloud 一步步实现广告系统] 22. 广告系统回顾总结
- python中df去重_Python中DataFrame去重
- VelocityTracker简要
- 【CodeForces - 1A】Theatre Square(水题,几何)(CODEFORCES,梦的开始)
- WORD设置别人只可阅读,不可更改文档?
- linux同一目录文件无法执行,linux – 无法在特定目录中执行文件
- mysql 42
- oracle数据库管理和日常维护,oracle数据库管理与维护
- http和https协议下,http可以正常下载,但是https却不能
- 积分商城功能表设计结构以及积分功能模块
- 代理服务器使用全攻略(转)
- nltk中文分句_如何改进NLTK的分句技术?
- traceroute出现*的分析
- 能上QQ不能打开网页的解决方法
- c语言入门之项目3.6——利用for循环输出一个直角三角形
- 张江创业者说 | 影创科技孙立:改变世界,从改变视野开始
- aucc2018插件_你的Au cc2018 新功能你都了解多少?
- 机器学习技法11: Gradient Boosted Decision Tree(GBDT)
- 2021年电工(初级)考试题及电工(初级)考试题库
热门文章
- 我中招了:解喝汽水问题
- 小马儿随笔十一:朋友一生一起走
- MindManager思维导图中文版免费下载使用教程
- 用了几年的 Fastjson,我最终替换成了Jackson!
- 架构篇:高可用 Redis 服务架构分析与搭建
- 运维定位服务故障时,前5分钟都在忙啥?
- 程序员如何转型项目经理?
- js 运行中断停止_如何终止JS继续运行??
- 百度地图手机端单触点单击和长按事件,解决部分手机(小米手机)地图单击事件失效,多触点、拖动依然触发长按的bug...
- 【BZOJ】3576: [Hnoi2014]江南乐