Qt4_写HTTP客户端

写HTTP客户端

QHttp类在Qt中实现了HTTP协议的客户端程序。它提供了各种各样的函数来执行绝大多数普通HTTP操作,包括get()和post(),并且还提供了一个发送任意HTTP请求指令的方式。会发现QFtp和QHttp之间存在很多相似之处。

QHttp类是异步工作的。当调用一个像get()或者post( )这样的函数时,它会立即返回,并且当控制权回到Qt事件循环时才会开始传输数据。这样就确保了在处理HTTP请求时,应用程序的用户界面可以始终保持响应。

我们将查看一个名为httpget 的控制台应用程序,以说明如何利用HTTP协议下载一个文件。这里将不再显示出头文件,因为它和前一节所使用的那个ftpget例子,不论在功能上还是实现过程上,都非常相似。

HttpGet::HttpGet(QObject *parent)
    : QObject(parent)
{
    connect(&http, SIGNAL(done(bool)), this, SLOT(httpDone(bool)));
}

在构造函数中,我们把QHttp对象的done(bool)信号与httpDone(bool)私有槽连接起来。

bool HttpGet::getFile(const QUrl &url)
{
    if (!url.isValid()) {
        std::cerr << "Error: Invalid URL" << std::endl;
        return false;
    }

    if (url.scheme() != "http") {
        std::cerr << "Error: URL must start with 'http:'" << std::endl;
        return false;
    }

    if (url.path().isEmpty()) {
        std::cerr << "Error: URL has no path" << std::endl;
        return false;
    }

    QString localFileName = QFileInfo(url.path()).fileName();
    if (localFileName.isEmpty())
        localFileName = "httpget.out";

    file.setFileName(localFileName);
    if (!file.open(QIODevice::WriteOnly)) {
        std::cerr << "Error: Cannot write file "
                  << qPrintable(file.fileName()) << ": "
                  << qPrintable(file.errorString()) << std::endl;
        return false;
    }

    http.setHost(url.host(), url.port(80));
    http.get(url.path(), &file);
    http.close();
    return true;
}

getFile()函数执行与之前所给出的FtpGet::getFile()一样可以执行同种类型的错误检查,并且采用相同的方式来命名文件的本地文件名。当从网站获得文件时,由于不必登录,所以只要设置主机和端口号(如果在URL中没有指定端口号,则采用默认的HTTP端口号80),就可将数据下载到文件中,因为QHttp::get()的第二个参数指定了输出信号的输人输出(IO)设备。

这些HTTP请求在Qt的事件循环中排队并且被异步执行。QHttp 的done(bool)信号表明了这些请求的完成情况,在构造函数中已经把这个信号与httpDone(bool)连接起来了。

void HttpGet::httpDone(bool error)
{
    if (error) {
        std::cerr << "Error: " << qPrintable(http.errorString())
                  << std::endl;
    } else {
        std::cerr << "File downloaded as "
                  << qPrintable(file.fileName()) << std::endl;
    }
    file.close();
    emit done();
}

一旦完成了这些HTTP请求,就关闭这个文件,并在有错误发生时通知用户。

它的main()函数与ftpget中曾使用过的主函数非常相似:

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QStringList args = QCoreApplication::arguments();

    if (args.count() != 2) {
        std::cerr << "Usage: httpget url" << std::endl
                  << "Example:" << std::endl
                  << "    httpget http://doc.trolltech.com/index.html"
                  << std::endl;
        return 1;
    }

    HttpGet getter;
    if (!getter.getFile(QUrl(args[1])))
        return 1;

    QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit()));

    return app.exec();
}

QHtp类提供了多种操作,包括setHost()、 get()、post()和head()。如果站点需要认证,则setUser()可以用来提供用户名和口令。QHttp 可以用程序员自编的套接字装置而不用其内部自带的QTcpSocket。这就使利用可靠的QtSslSocket来在SSL(加密套接字协议层)或TLS(加密传输协议层)上实现HTTP成为可能。

为了向CGI脚本发送一列"name=value"值对,可以使用post()函数:

http.setHost("www.example.com");
http.post("/cgi/somescript.py", "x=200&y=3320", &file);

既可以用8位的字符串来传递数据,也可以像QFile一样,通过传递一个开放的QIODevice来传递数据。为了获得更多的控制权,可以使用request()函数,它接收任意一个HTTP的标题和数据。例如:

QHttpRequestHeader header("POST", "/search.html");
header.setValue("Host", "www.trolltech.com");
header.setContentType("application/X-www-form-urlencoded");
http.setHost("www.trolltech.com");
http.request(header, "qt-interest=on&search=opengl");

当QHttp开始执行请求时,它会发射requestStarted(int)信号,而当这个请求完成时,会发射requestFinished(int, bool)信号。int 参数是标识请求的ID号。如果我们对个别请求的结果感兴趣,就可以在调用这些指令的时候保存ID号。了解并记录这些ID号可以为用户提供详细的反馈
信息。

在绝大多数应用程序中,我们仅仅想知道整个系列的请求是否已成功地完成执行。通过与done(bool)信号连接,就可以很简单地实现这一点,当请求序列变空时,就会发射该信号。

当有错误发生时,这个请求队列会被自动清空。但是如果在错误发生之后使用相同的QHttp对象调用新的请求,这些请求将会照常排队并被发送执行。

与QFtp一样,QHttp不仅提供了read()和readAll()函数,它还提供readyRead()信号,使我们不必指定某一输入/输出设备。

httpget.h

#ifndef HTTPGET_H
#define HTTPGET_H

#include <QFile>
#include <QHttp>

class QUrl;

class HttpGet : public QObject
{
    Q_OBJECT

public:
    HttpGet(QObject *parent = 0);

    bool getFile(const QUrl &url);

signals:
    void done();

private slots:
    void httpDone(bool error);

private:
    QHttp http;
    QFile file;
};

#endif

httpget.cpp

#include <QtCore>
#include <QtNetwork>
#include <iostream>

#include "httpget.h"

HttpGet::HttpGet(QObject *parent)
    : QObject(parent)
{
    connect(&http, SIGNAL(done(bool)), this, SLOT(httpDone(bool)));
}

bool HttpGet::getFile(const QUrl &url)
{
    if (!url.isValid()) {
        std::cerr << "Error: Invalid URL" << std::endl;
        return false;
    }

    if (url.scheme() != "http") {
        std::cerr << "Error: URL must start with 'http:'" << std::endl;
        return false;
    }

    if (url.path().isEmpty()) {
        std::cerr << "Error: URL has no path" << std::endl;
        return false;
    }

    QString localFileName = QFileInfo(url.path()).fileName();
    if (localFileName.isEmpty())
        localFileName = "httpget.out";

    file.setFileName(localFileName);
    if (!file.open(QIODevice::WriteOnly)) {
        std::cerr << "Error: Cannot write file "
                  << qPrintable(file.fileName()) << ": "
                  << qPrintable(file.errorString()) << std::endl;
        return false;
    }

    http.setHost(url.host(), url.port(80));
    http.get(url.path(), &file);
    http.close();
    return true;
}

void HttpGet::httpDone(bool error)
{
    if (error) {
        std::cerr << "Error: " << qPrintable(http.errorString())
                  << std::endl;
    } else {
        std::cerr << "File downloaded as "
                  << qPrintable(file.fileName()) << std::endl;
    }
    file.close();
    emit done();
}

main.cpp

#include <QtCore>
#include <iostream>

#include "httpget.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QStringList args = QCoreApplication::arguments();

    if (args.count() != 2) {
        std::cerr << "Usage: httpget url" << std::endl
                  << "Example:" << std::endl
                  << "    httpget http://doc.trolltech.com/index.html"
                  << std::endl;
        return 1;
    }

    HttpGet getter;
    if (!getter.getFile(QUrl(args[1])))
        return 1;

    QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit()));

    return app.exec();
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阳光开朗男孩

你的鼓励是我最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值