Qt之网络编程

简述

Qt Network模块提供的类允许编写 TCP/IP clients 和 servers。

其中包含一些低级别的类,例如:QTcpSocket、QTcpServer 和 QUdpSocket,表示低级的网络概念;一些高级别的类,例如:QNetworkRequest、QNetworkReply 和 QNetworkAccessManager,使用常见的协议执行网络操作;它还提供其他的类,例如:QNetworkConfiguration、QNetworkConfigurationManager 和QNetworkSession 用于承载管理。

用法

要链接到网络模块,需要在qmake项目文件中添加:

QT += network1

如果你打算在应用程序中使用Qt Network类,使用下面的 include 语句:

#include <QtNetwork>1

Qt 网络编程类

Qt Network 中的 C++ 类列表:

描述
QAbstractNetworkCache 为缓存实现的接口
QAbstractSocket 包含所有 socket 类型的基础功能
QAuthenticator 认证对象
QDnsDomainNameRecord 存储关于域名记录的信息
QDnsHostAddressRecord 存储关于主机地址记录的信息
QDnsLookup 表示一个DNS查询
QDnsMailExchangeRecord 存储有关 DNS MX 记录的信息
QDnsServiceRecord 存储有关 DNS SRV 记录的信息
QDnsTextRecord 存储有关 DNS TXT 记录的信息
QHostAddress IP地址
QHostInfo 主机名查询静态函数
QHttpMultiPart 类似于一个 MIME 多个部分消息,通过HTTP发送
QHttpPart 持有一个 body 部分,用于 HTTP 多个部分的 MINE 消息
QLocalServer 本地 socket 依赖的 server
QLocalSocket 本地 socket
QNetworkAccessManager 允许程序发送网络请求和接收响应
QNetworkAddressEntry 存储一个 IP 地址,通过网络接口的支持,连同相关的网络掩码和广播地址
QNetworkCacheMetaData 缓存信息
QNetworkConfiguration 一个或多个配置接入点的抽象概念
QNetworkConfigurationManager 管理由系统提供的网络配置
QNetworkCookie 管理由系统提供的网络配置
QNetworkCookieJar 实现 QNetworkCookie 对象的一个简单jar
QNetworkDiskCache 非常基本的磁盘缓存
QNetworkInterface 主机的IP地址和网络接口列表
QNetworkProxy 网络层代理
QNetworkProxyFactory 精细的代理选择
QNetworkProxyQuery 用于查询一个 socket 的代理设置
QNetworkReply 包含 QNetworkAccessManager 发送的请求数据和消息头
QNetworkRequest 持有一个 QNetworkAccessManager 发送的请求
QNetworkSession 控制系统的接入点并启用例的会话管理,为了当多个客户端访问相同的接入点
QSslCertificate 用于 X509 证书的方便 API
QSslCertificateExtension 用于访问 X509 证书扩展的API
QSslCipher 代表一个SSL加密密码
QSslConfiguration 持有 SSL 连接的配置及状态
QSslEllipticCurve 代表了一种椭圆曲线使用椭圆曲线密码算法
QSslError SSL 错误
QSslKey 私钥和公钥的接口
QSslPreSharedKeyAuthenticator 预共享密钥认证数据(PSK)密码套件
QSslSocket clients 和 servers 的 SSL 加密 socket
QTcpServer 基于 TCP 的 server
QTcpSocket TCP socket
QUdpSocket UDP socket

HTTP 和 FTP 高级网络操作

网络访问 API 是 一个用于执行常见的网络操作的类集合。该 API 在特定操作和协议使用上(例如:通过 HTTP 获取和发布数据)提供了一个抽象层,并且只有共有类、函数和信号用于一般或高级别的概念。

QNetworkRequest 类用于表示网络请求,它也充当一个与请求信息相关的通用容器,例如:任何头信息和使用的加密相关的信息。当一个 request 对象被构造时,指定的 URL 决定所用的协议。目前 HTTP、FTP 和本地文件 URLs 支持上传和下载。

QNetworkAccessManager 类用于协调网络操作,一旦创建一个 request,该类用来发出请求并发射信号来报告它的进度。manager 也协调 cookies 的使用在 client 存储数据、请求的身份验证、代理的使用。

QNetworkReply 类用于网络请求的响应,当一个 request 被发出后,QNetworkAccessManager 就会创建相应的响应,通过 QNetworkReply 提供的信号可以单独监听每个响应,或者使用 manager 的信号。由于 QNetworkReply 是 QIODevice 的一个子类,可以同步或异步处理响应;也就是说,阻塞或非阻塞操作。

每个应用程序或库都可以创建一个或多个 QNetworkAccessManager 实例来处理网络通信。

TCP(QTcpSocket和QTcpServer)

TCP(Transmission Control Protocol - 传输控制协议)是一个底层网络协议,被用于大多数互联网协议,包括:HTTP 和 FTP,进行数据传输。它是一种面向连接的、可靠的、基于字节流的传输层通信协议,特别适合数据的连续传输。

这里写图片描述

QTcpSocket 类为 TCP 提供了一个接口。可以使用 QTcpSocket 实现标准网络协议,例如:POP3、SMTP 和 NNTP,也可以自定义协议。

在任何数据传输开始之前,必须建立一个 TCP 连接到远程的主机和端口。一旦建立了连接,对等的 IP 地址和端口可以通过 QTcpSocket::peerAddress() 和 QTcpSocket::peerPort() 来获取。在任何时候,任何一方都可以关闭连接,这时数据传输将立即停止。

QTcpSocket 异步执行,并发出信号以报告状态变化和错误,就像 QNetworkAccessManager 一样。它依赖于事件循环,以检测输入的数据,并自动地刷新传出数据。可以使用 QTcpSocket::write() 将数据写入到 socket,并使用 QTcpSocket::read() 来读取。QTcpSocket 表示两个独立的数据流:一个用于读取,一个用于写入。

由于 QTcpSocket 继承自 QIODevice,可以同 QTextStream、QDataStream 一起使用它。当从一个 QTcpSocket 读取时,必须先调用 QTcpSocket::bytesAvailable() 以确保有足够可用的数据。

如果需要处理传入的 TCP 连接(例如:在一个 server 应用程序),使用 QTcpServer 类。调用 QTcpServer::listen() 来设置 server,并连接 QTcpServer::newConnection() 信号,一旦有 client 连接进入,就会发射此信号。在你的槽函数中,调用 QTcpServer::nextPendingConnection() 来接受连接,并使用返回的 QTcpSocket 与 client 通信。

虽然它的大部分函数异步执行,它可以使用 QTcpSocket 同步(即:阻塞)。为了获取阻塞行为,调用 QTcpSocket 的 waitFor…() 函数,这将挂起调用线程,直到信号发出。例如:调用非阻塞函数 QTcpSocket::connectToHost() 之后,调用 QTcpSocket::waitForConnected() 阻塞线程,直到 connected() 信号被发射。

同步 sockets 往往用于更简单的流控制,waitFor…() 函数的主要缺点是,当一个 waitFor…() 阻塞时,事件就不会被处理。如果在 GUI 线程中使用,这可能冻结应用程序的用户界面。出于这个原因,建议只在非 GUI 线程中使用同步 sockets。当同步使用时,QTcpSocket 并不需要一个事件循环。

Fortune Client 和 Fortune Server 示例展示了如何使用 QTcpSocket 和 QTcpServer 来写 TCP client-server 应用程序。参考 Blocking Fortune Client 示例,了解如何在一个独立的线程中(没有使用事件循环)使用同步 QTcpSocket;参考 Threaded Fortune Server 示例,了解一个多线程 TCP server,其每个激活的 client 都有一个线程。

UDP(QUdpSocket)

UDP(User Datagram Protocol - 用户数据报协议)是一个轻量级的、不可靠的、面向数据报、无连接的协议。当可靠性不重要时,可以使用它。例如:用于报告每天时间的一个 server 可以选择 UDP,如果每天时间的一个数据报丢失了,client 可以简单地发出另外一个请求。

这里写图片描述

QUdpSocket 类允许发送和接收 UDP 数据报,继承自 QAbstractSocket,并因此享有 QTcpSocket 的大部分接口。主要区别是 QUdpSocket 传输数据作为一个数据报,而非一个连续的数据流。简而言之,数据报是一个有限大小的数据包(通常小于 512 字节),包含数据报发送方和接收方的IP地址和端口,除了数据传输。

QUdpSocket 支持 IPv4 广播。广播通常是用于实现网络发现协议。例如:发现哪一台网络主机有较空闲的硬盘空间。一个主机广播数据报给网络,所有其他主机接收。每个主机接收请求,然后发送应答(当前的空闲磁盘空间)给发送方。发起人等待,直到它收到所有主机的回复,并可以选择有较大空间的 server 来存储数据。要广播数据报,只需简单地将其发送到特殊地址 QHostAddress::Broadcast(255.255.255.255),或者到你本地的网络广播地址。

QUdpSocket::bind() 准备了socket 用于接受传入数据包,很像用于 TCP servers 的 QTcpServer::listen()。当一个或多个数据报到达时,QUdpSocket 会发射 readyRead() 信号,调用 QUdpSocket::readDatagram() 来读取数据报。

Broadcast Sender 和 Broadcast Receiver 示例展示了如何使用 Qt 写一个 UDP 发送者和接受者。

QUdpSocket 还支持多播。Multicast Sender 和 Multicast Receiver 示例展示了如何写 UDP 多播 clients。

QHostInfo 解析主机名

在建立一个网络连接之前,QTcpSocket 和 QUdpSocket 会执行一个名称查找,将你所连接到的主机名称转换成 IP 地址。这个操作通常使用 DNS(Domain Name Service - 域名服务)协议执行。

QHostInfo 提供了一个静态函数,通过调用 QHostInfo::lookupHost(),参数为:一个主机名、一个 QObject 指针和一个槽函数签名。QHostInfo 将执行指定名称的查找,当结果准备就绪时,调用槽函数。实际的查询在一个单独的线程中完成,利用操作系统的方法来执行名称查找。

QHostInfo 还提供了一个静态函数 QHostInfo::fromName() ,需要将主机名作为参数,并返回结果。这种情况下,名称查询的执行与调用者处于相同的线程中。这对于非 GUI 应用程序或在一个单独的、非 GUI 线程中做名称查找是比较有用的(在 GUI 线程中调用这个函数可能会导致你的用户界面冻结而功能块执行查找)。

网络代理

Qt 网络通信可以通过代理来执行,将直接或过滤本地和远程连接之间的网络流量。

QNetworkProxy 类表示个人代理,用于描述和配置到一个代理的连接。代理类型,操作在网络通信支持的不同级别上,SOCKS 5 支持允许网络流量的代理在低级别上, HTTP 和 FTP 代理工作在协议级别上。参考 QNetworkProxy::ProxyType 获得更多信息。

代理可以用于每个socket 或应用程序中所有网络通信。一个新开的 socket 在它连接之前,可以通过调用 QAbstractSocket::setProxy() 函数使用代理。通过使用 QNetworkProxy::setApplicationProxy() 函数,可以在程序范围内为后续的 socket 连接启用代理。

代理工厂用于创建代理使用的策略。QNetworkProxyFactory 提供的代理基于查询特定的代理类型。查询本身以 QNetworkProxyQuery 对象进行编码,该对象启用代理可以被选择基于主要标准,例如:代理的用途(TCP、UDP、TCP server、URL request),本地端口、远程主机和端口、使用的协议(HTTP、FTP等)。

QNetworkProxyFactory::proxyForQuery() 用于直接查询工厂。通过传递一个工厂给 QNetworkProxyFactory::setApplicationProxyFactory(),可以实现程序范围内的代理策略,通过子类化QNetworkProxyFactory,可以创建一个自定义代理政策。

承载管理

承载管理控制设备的连接状态,这样,应用程序可以启动或停止网络接口,并且在接入点之间透明地游荡。

QNetworkConfigurationManager 类管理已知设备的网络配置列表,网络配置由 QNetworkConfiguration 类表示,描述了一组用于启动网络接口的参数。

通过打开基于一个网路配置的 QNetworkSession,一个网络接口被打开。大多数情况,创建一个基于平台指定默认网络配置的网络会话是合适的。默认网络配置由 QNetworkConfigurationManager::defaultConfiguration() 函数返回。

某些平台上,在执行任何网络操作之前,要求应用程序打开网络会话。可以通过QNetworkConfigurationManager::capabilities()函数返回的值进行测试,判断是否包含给出的QNetworkConfigurationManager::NetworkSessionRequired标志。