写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_OBJECTpublic: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();
}

Qt4_写HTTP客户端相关推荐

  1. Qt4_写FTP客户端

    写FTP客户端 QFtp类在Qt中实现了FTP协议的客户端程序,它提供了非常多的函数来执行多数常见的FTP操作,同时还可以执行任意的FTP指令. QFtp类是异步工作的.若调用一个像get()或者pu ...

  2. python编写ftp客户端_用Python写FTP客户端程序

    0 前言: ftp客户端相信大家都用过,那么我们为什么还要用Python写ftp客户端呢? 我想有两个原因: 一是写出更好的ftp客户端应用程序,方便大家使用: 二是定制一些特殊服务,例如每天定时下载 ...

  3. 自己动手写邮件客户端(1)

    自己动手写邮件客户端(1) --命令行测试发邮件 参考 RFC中文 环境 系统: win10 语言: java 简要流程 建立一个到邮件服务器的连接(在此使用smtp.163.com:25) Sock ...

  4. 使用java语言基于SMTP协议手写邮件客户端

    使用java语言基于SMTP协议手写邮件客户端 1. 说明 电子邮件是互联网上常见的应用,他是互联网早期的产品,直至今日依然受到广大用户的喜爱(在中国可能因为文化背景不同,电子邮件只在办公的时候常用) ...

  5. Qt4_写TCP客户/服务器应用程序

    写TCP客户/服务器应用程序 QTcpSocket和QTcpServer类可以用来实现TCP客户端和服务器.TCP是一个传输协议,它构成了包括FTP和HTTP等很多应用程序层的因特网协议基础,它也可以 ...

  6. 如何写好客户端技术方案

    文章目录 一. 背景 二. 为什么要写技术方案 三. 写技术方案需要注意哪些点 四. 技术方案模板 1. 技术文档 描述 1.1. 项目组相关成员 1.2. 设计准备 1.2.1. 需求及产品设计 1 ...

  7. java写soap客户端_Java:简单的SOAP客户端

    我正在寻找一个用于 Java的SOAP客户端. Apache Axis对我来说看起来很blo肿.我不明白为什么Java必须如此复杂.例如,在PHP中,我所要做的就是: $global_service_ ...

  8. 如何根据接口写一个客户端进行发单测试?

    第一步,先写一个jsp页面,定义jsp将form表单提交给SiglePaymentServlet <%@ page language="java" contentType=& ...

  9. ruby非阻塞式socket编程--写飞信客户端的经验总结

    最近在使用ruby编写飞信客户端时,遇到TCPSocket的阻塞问题,socket总是直接挂死或者超时失败.经过一番探索,下面的方法颇有奇效,终于可以成功发短信啦: require "soc ...

最新文章

  1. SVD与PCA的区别
  2. php 的常量能不能删除,php能删除常量吗
  3. react中setState有三种用法
  4. .NetCore跨域
  5. 类似flashget的浮动窗口的实现
  6. android studio 新建工程慢,关于AndroidStudio新建与编译项目速度慢解决办法
  7. python 连接mysql_使用MySQL
  8. linux disk 清除数据,如何在Linux中使用TestDisk恢复已删除的文件
  9. mysql自建知识库_Mysql 搭建主從復制
  10. 【BZOJ4710】[JSOI2011]分特产(容斥)
  11. linux+npm+v+报错_linux下安装npm
  12. ubuntu16.04登录后无dash,无启动栏launch,无menu bar,只有桌面背景解决办法
  13. linux 下分离 debuginfo 到独立文件.
  14. 【MATLAB信号处理】连续时间信号与系统的频域分析
  15. 中国最爱喝奶茶的城市找到了
  16. Java程序二进制转化为十进制_用java程序实现二进制像十进制转化或十进 – 手机爱问...
  17. Assassin暗杀者-自用短小精悍的webshell管理工具分享
  18. 2020-05-19
  19. 聊聊同步/异步/阻塞/非阻塞(举栗子说明)
  20. SpringBoot集成redis的LBS功能

热门文章

  1. 网络-IP/子网掩码/端口
  2. MySQL01:MySQL概述
  3. python的for语句怎么写_Python日常之——不要再写循环了!
  4. 单元测试用例_前端单元测试实践
  5. Tensorflow安装问题: Could not find a version that satisfies the requirement tensorflow
  6. Git--rebase合并提交
  7. 前端(jQuery)(10)-- jQuery标签切换
  8. Java web servers 间是如何实现 session 同步的
  9. IDEA 分享项目到 Git@OSC/GitHub
  10. 时隔2月,我的第二篇