QT分析之网络编程(六)

在动手分析前,简单介绍一下HTTP协议。HTTP协议是一种为分布式,合作式,超媒体信息系统。它是一种通用的,无状态(stateless)的协议,除了应用于超文本传输外,它也可以应用于诸如名称服务器和分布对象管理系统之类的系统,这可以通过扩展它的请求方法,错误代码和报头来实现。HTTP的一个特点是数据表现形式是可输入的和可协商性的,这就允许系统能被建立而独立于数据传输。HTTP在1990年WWW全球信息刚刚起步的时候就得到了应用。该规范定义的协议用“HTTP/1.1”表示,是对RFC2608[33]的更新。
HTTP协议是通过定义一序列的动作(协议文本中称为方法),来完成数据的传输通信。HTTP1.1版本中有这些方法:get、post、head、options、put、delete、trace、connect。

get方法用于获取URI资源,是最为常用的一种方法。

post方法用于向指定URI提交内容,服务器端响应其行为,该方法也极为常用。

head方法向URI发送请求,仅仅只需要获得响应的协议头。

put方法用于向URI发送请求,若URI不存在,则要求服务器端根据请求创建资源。当URI存在时,服务器端必须接受请求内容,将其作为URI资源的修改后版本。

delete方法用于删除URI标识的指定资源。

trace方法用于激活服务器端对请求的循环反馈,反馈作为http响应的正文内容被传输回客户端。

connect方法通常被用于使用代理连接。

更详细的内容请查看相关资料。

回到QT系统,manager->get()调用其实就是HTTP/1.1协议中get方法的实现。

QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
{
    return d_func()->postProcess(createRequest(QNetworkAccessManager::GetOperation, request));
}
上面的一行程序中有两个调用:

1、QNetworkAccessManager::createRequest()

2、QNetworkAccessManagerPrivate::postProcess()

先来看createRequest(),两个参数:第一个参数表示使用Get方法;第二个参数是目标网址。

QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op,
                                                    const QNetworkRequest &req,
                                                    QIODevice *outgoingData)
{
    Q_D(QNetworkAccessManager);
    QNetworkRequest request = req;
    if (!request.header(QNetworkRequest::ContentLengthHeader).isValid() &&
        outgoingData && !outgoingData->isSequential()) {
        // request has no Content-Length
        // but the data that is outgoing is random-access
        request.setHeader(QNetworkRequest::ContentLengthHeader, outgoingData->size());
    }
    if (d->cookieJar) {
        QList<QNetworkCookie> cookies = d->cookieJar->cookiesForUrl(request.url());
        if (!cookies.isEmpty())
            request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
    }

    // first step: create the reply
    QUrl url = request.url();
    QNetworkReplyImpl *reply = new QNetworkReplyImpl(this);
    QNetworkReplyImplPrivate *priv = reply->d_func();
    priv->manager = this;

    // second step: fetch cached credentials
    QNetworkAuthenticationCredential *cred = d->fetchCachedCredentials(url);
    if (cred) {
        url.setUserName(cred->user);
        url.setPassword(cred->password);
        priv->urlForLastAuthentication = url;
    }

    // third step: setup the reply
    priv->setup(op, request, outgoingData);
#ifndef QT_NO_NETWORKPROXY
    QList<QNetworkProxy> proxyList = d->queryProxy(QNetworkProxyQuery(request.url()));
    priv->proxyList = proxyList;
#endif

    // fourth step: find a backend
    priv->backend = d->findBackend(op, request);
    if (priv->backend) {
        priv->backend->setParent(reply);
        priv->backend->reply = priv;
    }

#ifndef QT_NO_OPENSSL
    reply->setSslConfiguration(request.sslConfiguration());
#endif
    return reply;
}
代码比较长,主要做了这些事情:

1、设定HTTP请求的头信息(例如客户端请求内容的长度、Cookie等)

2、生成并初始化Reply对象(实际是QNetworkReplyImpl对象)

3、获取本地缓存的认证信息(如果有的话)

4、设定Reply

5、获取一个backend实体

6、如果支持OPENSSL的话,设定SSL的配置

暂时先放一边后面再对createRequest()做进一步的分析,再来看postProcess()
QNetworkReply *QNetworkAccessManagerPrivate::postProcess(QNetworkReply *reply)
{
    Q_Q(QNetworkAccessManager);
    QNetworkReplyPrivate::setManager(reply, q);
    q->connect(reply, SIGNAL(finished()), SLOT(_q_replyFinished()));
#ifndef QT_NO_OPENSSL
    /* In case we're compiled without SSL support, we don't have this signal and we need to
     * avoid getting a connection error. */
    q->connect(reply, SIGNAL(sslErrors(QList<QSslError>)), SLOT(_q_replySslErrors(QList<QSslError>)));
#endif

    return reply;
}
简单来说就做了一件事情,把QNetworkReply的信号(finished、sslErrors)与QNetworkAccessManager的槽连接起来。

时间: 2024-10-02 18:32:45

QT分析之网络编程(六)的相关文章

QT分析之网络编程(一)

首先对Windows下的网络编程总结一下: 如果是服务器,其WinSDK调用分别为: WSAStartup() -> socket() -> htons() / htonl() -> bind() -> listen() -> accept() -> recv() / send() -> closesocket() -> WSACleanup() 如果是客户端程序,其调用序列为: WSAStartup() -> socket() -> htons

QT分析之网络编程(二)

前面分析(一)之前没有看QT自带的文档,看了doc之后对QT的网络体系有一个大致的了解: QNatvieSocketEnginePrivate是OS相关的API封装,和QNativeSocketEngine一起构成具体平台SOCKET实现: QTcpSocket.QUdpSocket.QTcpServer构成底层的应用API:QSslSocket是SSL加密相关API: QHttp.QFtp构成高层次应该API: QNetworkAccessManager.QNetworkRequest.QNe

QT分析之网络编程(七)

接上面,进一步分析QNetworkAccessManager::createRequest()的实现.去除不重要的分支末节,看其调用的QNetworkReplyImplPrivate::setup()和QNetworkAccessManagerPrivate::findBackend()的代码. void QNetworkReplyImplPrivate::setup(QNetworkAccessManager::Operation op, const QNetworkRequest &req,

QT分析之网络编程(五)

今天分析QNetworkAccessManager.QNetworkRequest和QNetworkReply组成的高级抽象API序列.在动手之前,把doc中有关QNetworkAccessManager的介绍看了一遍.其使用方法大致是: QNetworkAccessManager * manager = new QNetworkAccessManager(this); QNetworkRequest request; request.setUrl(QUrl("http://www.baidu.

QT分析之网络编程(八)

话说昨日走到QNetworkReplyImplPrivate::_q_startOperation(),勾引出QNetworkAccessHttpBackend::open(),今日接着欣赏QT之美丽. void QNetworkAccessHttpBackend::open() {     QUrl url = request().url();     bool encrypt = url.scheme().toLower() == QLatin1String("https");  

QT分析之网络编程(四)

前面分析中,一个问题一直没有解决:新生成的SOCKET是什么时候加入WSASelect()的?另外还有一个不是很大的问题,close流程. 在QEventDispatcherWin32Private::doWsaAsyncSelect()中WSAAsyncSelect()设置一个断点,观察call stack: >    QtCored4.dll!QEventDispatcherWin32Private::doWsaAsyncSelect(int socket=0x00001628)  行633

QT分析之网络编程(三)

3.读取信息 在QAbstractSocket中,有两个成员是收发数据用的:readData().writeData() readData()有两种读取方式:有缓冲和无缓冲方式.基本原理是一致的,简单其见只分析无缓冲直接读取方式. qint64 QAbstractSocket::readData(char *data, qint64 maxSize) {     Q_D(QAbstractSocket);     if (d->socketEngine && !d->socke

实例分析J2ME网络编程的两种方法

编程|网络 本文描述了在J2me中开发主要使用的网络连接方法,分别详细介绍了使用http和socket两种方法. HttpConnection 首先我们先来看一个简单的例子吧: 主要用到的java包: javax.microedition.io.*; public String requestGET(String URLString,String URL) throws IOException{ // ===============================================

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

 1 新建一个项目:TCPServer.pro A  修改TCPServer.pro,注意:如果是想使用网络库,需要加上network SOURCES += \     TcpServer.cpp \     TcpClient.cpp   HEADERS += \     TcpServer.h \     TcpClient.h   QT += gui widgets network   CONFIG += C++11 B 新建如下文件,因为要用到网络库,所以加上network C 编写